diff --git a/1.3.2/files/browsers.json b/1.3.2/files/browsers.json new file mode 100644 index 0000000..25fc142 --- /dev/null +++ b/1.3.2/files/browsers.json @@ -0,0 +1,446 @@ +{ + "firefox": { + "default": "58.0", + "versions": { + "58.0": { + "image": "selenoid/vnc:firefox_58.0", + "port": "4444", + "path": "/wd/hub" + }, + "57.0": { + "image": "selenoid/vnc:firefox_57.0", + "port": "4444", + "path": "/wd/hub" + }, + "56.0": { + "image": "selenoid/vnc:firefox_56.0", + "port": "4444", + "path": "/wd/hub" + }, + "55.0": { + "image": "selenoid/vnc:firefox_55.0", + "port": "4444", + "path": "/wd/hub" + }, + "54.0": { + "image": "selenoid/vnc:firefox_54.0", + "port": "4444", + "path": "/wd/hub" + }, + "53.0": { + "image": "selenoid/vnc:firefox_53.0", + "port": "4444", + "path": "/wd/hub" + }, + "52.0": { + "image": "selenoid/vnc:firefox_52.0", + "port": "4444", + "path": "/wd/hub" + }, + "51.0": { + "image": "selenoid/vnc:firefox_51.0", + "port": "4444", + "path": "/wd/hub" + }, + "50.0": { + "image": "selenoid/vnc:firefox_50.0", + "port": "4444", + "path": "/wd/hub" + }, + "49.0": { + "image": "selenoid/vnc:firefox_49.0", + "port": "4444", + "path": "/wd/hub" + }, + "48.0": { + "image": "selenoid/vnc:firefox_48.0", + "port": "4444", + "path": "/wd/hub" + }, + "47.0": { + "image": "selenoid/vnc:firefox_47.0", + "port": "4444", + "path": "/wd/hub" + }, + "46.0": { + "image": "selenoid/vnc:firefox_46.0", + "port": "4444", + "path": "/wd/hub" + }, + "45.0": { + "image": "selenoid/vnc:firefox_45.0", + "port": "4444", + "path": "/wd/hub" + }, + "44.0": { + "image": "selenoid/vnc:firefox_44.0", + "port": "4444", + "path": "/wd/hub" + }, + "43.0": { + "image": "selenoid/vnc:firefox_43.0", + "port": "4444", + "path": "/wd/hub" + }, + "42.0": { + "image": "selenoid/vnc:firefox_42.0", + "port": "4444", + "path": "/wd/hub" + }, + "41.0": { + "image": "selenoid/vnc:firefox_41.0", + "port": "4444", + "path": "/wd/hub" + }, + "40.0": { + "image": "selenoid/vnc:firefox_40.0", + "port": "4444", + "path": "/wd/hub" + }, + "39.0": { + "image": "selenoid/vnc:firefox_39.0", + "port": "4444", + "path": "/wd/hub" + }, + "38.0": { + "image": "selenoid/vnc:firefox_38.0", + "port": "4444", + "path": "/wd/hub" + }, + "37.0": { + "image": "selenoid/vnc:firefox_37.0", + "port": "4444", + "path": "/wd/hub" + }, + "36.0": { + "image": "selenoid/vnc:firefox_36.0", + "port": "4444", + "path": "/wd/hub" + }, + "35.0": { + "image": "selenoid/vnc:firefox_35.0", + "port": "4444", + "path": "/wd/hub" + }, + "34.0": { + "image": "selenoid/vnc:firefox_34.0", + "port": "4444", + "path": "/wd/hub" + }, + "33.0": { + "image": "selenoid/vnc:firefox_33.0", + "port": "4444", + "path": "/wd/hub" + }, + "32.0": { + "image": "selenoid/vnc:firefox_32.0", + "port": "4444", + "path": "/wd/hub" + }, + "31.0": { + "image": "selenoid/vnc:firefox_31.0", + "port": "4444", + "path": "/wd/hub" + }, + "30.0": { + "image": "selenoid/vnc:firefox_30.0", + "port": "4444", + "path": "/wd/hub" + }, + "29.0": { + "image": "selenoid/vnc:firefox_29.0", + "port": "4444", + "path": "/wd/hub" + }, + "28.0": { + "image": "selenoid/vnc:firefox_28.0", + "port": "4444", + "path": "/wd/hub" + }, + "27.0": { + "image": "selenoid/vnc:firefox_27.0", + "port": "4444", + "path": "/wd/hub" + }, + "26.0": { + "image": "selenoid/vnc:firefox_26.0", + "port": "4444", + "path": "/wd/hub" + }, + "25.0": { + "image": "selenoid/vnc:firefox_25.0", + "port": "4444", + "path": "/wd/hub" + }, + "24.0": { + "image": "selenoid/vnc:firefox_24.0", + "port": "4444", + "path": "/wd/hub" + }, + "23.0": { + "image": "selenoid/vnc:firefox_23.0", + "port": "4444", + "path": "/wd/hub" + }, + "22.0": { + "image": "selenoid/vnc:firefox_22.0", + "port": "4444", + "path": "/wd/hub" + }, + "21.0": { + "image": "selenoid/vnc:firefox_21.0", + "port": "4444", + "path": "/wd/hub" + }, + "20.0": { + "image": "selenoid/vnc:firefox_20.0", + "port": "4444", + "path": "/wd/hub" + }, + "19.0": { + "image": "selenoid/vnc:firefox_19.0", + "port": "4444", + "path": "/wd/hub" + }, + "18.0": { + "image": "selenoid/vnc:firefox_18.0", + "port": "4444", + "path": "/wd/hub" + }, + "17.0": { + "image": "selenoid/vnc:firefox_17.0", + "port": "4444", + "path": "/wd/hub" + }, + "16.0": { + "image": "selenoid/vnc:firefox_16.0", + "port": "4444", + "path": "/wd/hub" + }, + "15.0": { + "image": "selenoid/vnc:firefox_15.0", + "port": "4444", + "path": "/wd/hub" + }, + "14.0": { + "image": "selenoid/vnc:firefox_14.0", + "port": "4444", + "path": "/wd/hub" + }, + "13.0": { + "image": "selenoid/vnc:firefox_13.0", + "port": "4444", + "path": "/wd/hub" + }, + "12.0": { + "image": "selenoid/vnc:firefox_12.0", + "port": "4444", + "path": "/wd/hub" + }, + "11.0": { + "image": "selenoid/vnc:firefox_11.0", + "port": "4444", + "path": "/wd/hub" + }, + "10.0": { + "image": "selenoid/vnc:firefox_10.0", + "port": "4444", + "path": "/wd/hub" + }, + "9.0": { + "image": "selenoid/vnc:firefox_9.0", + "port": "4444", + "path": "/wd/hub" + }, + "8.0": { + "image": "selenoid/vnc:firefox_8.0", + "port": "4444", + "path": "/wd/hub" + }, + "7.0": { + "image": "selenoid/vnc:firefox_7.0", + "port": "4444", + "path": "/wd/hub" + }, + "6.0": { + "image": "selenoid/vnc:firefox_6.0", + "port": "4444", + "path": "/wd/hub" + }, + "5.0": { + "image": "selenoid/vnc:firefox_5.0", + "port": "4444", + "path": "/wd/hub" + }, + "4.0": { + "image": "selenoid/vnc:firefox_4.0", + "port": "4444", + "path": "/wd/hub" + }, + "3.6": { + "image": "selenoid/vnc:firefox_3.6", + "port": "4444", + "path": "/wd/hub" + } + } + }, + "chrome": { + "default": "65.0", + "versions": { + "65.0": { + "image": "selenoid/vnc:chrome_65.0", + "port": "4444" + }, + "64.0": { + "image": "selenoid/vnc:chrome_64.0", + "port": "4444" + }, + "63.0": { + "image": "selenoid/vnc:chrome_63.0", + "port": "4444" + }, + "62.0": { + "image": "selenoid/vnc:chrome_62.0", + "port": "4444" + }, + "61.0": { + "image": "selenoid/vnc:chrome_61.0", + "port": "4444" + }, + "60.0": { + "image": "selenoid/vnc:chrome_60.0", + "port": "4444" + }, + "59.0": { + "image": "selenoid/vnc:chrome_59.0", + "port": "4444" + }, + "58.0": { + "image": "selenoid/vnc:chrome_58.0", + "port": "4444" + }, + "57.0": { + "image": "selenoid/vnc:chrome_57.0", + "port": "4444" + }, + "56.0": { + "image": "selenoid/vnc:chrome_56.0", + "port": "4444" + }, + "55.0": { + "image": "selenoid/vnc:chrome_55.0", + "port": "4444" + }, + "54.0": { + "image": "selenoid/vnc:chrome_54.0", + "port": "4444" + }, + "53.0": { + "image": "selenoid/vnc:chrome_53.0", + "port": "4444" + }, + "52.0": { + "image": "selenoid/vnc:chrome_52.0", + "port": "4444" + }, + "51.0": { + "image": "selenoid/vnc:chrome_51.0", + "port": "4444" + }, + "50.0": { + "image": "selenoid/vnc:chrome_50.0", + "port": "4444" + }, + "49.0": { + "image": "selenoid/vnc:chrome_49.0", + "port": "4444" + }, + "48.0": { + "image": "selenoid/vnc:chrome_48.0", + "port": "4444" + } + } + }, + "opera": { + "default": "50.0", + "versions": { + "50.0": { + "image": "selenoid/vnc:opera_50.0", + "port": "4444" + }, + "49.0": { + "image": "selenoid/vnc:opera_49.0", + "port": "4444" + }, + "48.0": { + "image": "selenoid/vnc:opera_48.0", + "port": "4444" + }, + "47.0": { + "image": "selenoid/vnc:opera_47.0", + "port": "4444" + }, + "46.0": { + "image": "selenoid/vnc:opera_46.0", + "port": "4444" + }, + "45.0": { + "image": "selenoid/vnc:opera_45.0", + "port": "4444" + }, + "44.0": { + "image": "selenoid/vnc:opera_44.0", + "port": "4444" + }, + "43.0": { + "image": "selenoid/vnc:opera_43.0", + "port": "4444" + }, + "42.0": { + "image": "selenoid/vnc:opera_42.0", + "port": "4444" + }, + "41.0": { + "image": "selenoid/vnc:opera_41.0", + "port": "4444" + }, + "40.0": { + "image": "selenoid/vnc:opera_40.0", + "port": "4444" + }, + "39.0": { + "image": "selenoid/vnc:opera_39.0", + "port": "4444" + }, + "38.0": { + "image": "selenoid/vnc:opera_38.0", + "port": "4444" + }, + "37.0": { + "image": "selenoid/vnc:opera_37.0", + "port": "4444" + }, + "36.0": { + "image": "selenoid/vnc:opera_36.0", + "port": "4444" + }, + "35.0": { + "image": "selenoid/vnc:opera_35.0", + "port": "4444" + }, + "34.0": { + "image": "selenoid/vnc:opera_34.0", + "port": "4444" + }, + "33.0": { + "image": "selenoid/vnc:opera_33.0", + "port": "4444" + }, + "12.1": { + "image": "selenoid/vnc:opera_12.1", + "port": "4444", + "path": "/wd/hub" + } + } + } +} \ No newline at end of file diff --git a/1.3.2/files/moon-api.yaml b/1.3.2/files/moon-api.yaml new file mode 100644 index 0000000..8fa396c --- /dev/null +++ b/1.3.2/files/moon-api.yaml @@ -0,0 +1,45 @@ +kind: Service +apiVersion: v1 +metadata: + name: moon-api +spec: + selector: + app: moon-api + ports: + - protocol: TCP + port: 8080 + type: NodePort +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: moon-api +spec: + replicas: 1 + template: + metadata: + labels: + app: moon-api + spec: + containers: + - name: moon-api + image: aerokube/moon-api:1.3.2 + resources: + limits: + cpu: "0.25" + memory: "128Mi" + requests: + cpu: "0.1" + memory: "64Mi" + ports: + - containerPort: 8080 + volumeMounts: + - name: quota + mountPath: /quota + volumes: + - name: quota + configMap: + name: quota + - name: users + secret: + secretName: users diff --git a/1.3.2/files/moon-config/service.json b/1.3.2/files/moon-config/service.json new file mode 100644 index 0000000..1773f60 --- /dev/null +++ b/1.3.2/files/moon-config/service.json @@ -0,0 +1,7 @@ +{ + "images": { + "videoRecorder": "aerokube/moon-video-recorder:devel", + "defender": "aerokube/defender:devel", + "logger": "aerokube/logger:devel" + } +} diff --git a/1.3.2/files/moon-openshift.yaml b/1.3.2/files/moon-openshift.yaml new file mode 100644 index 0000000..e1a6b67 --- /dev/null +++ b/1.3.2/files/moon-openshift.yaml @@ -0,0 +1,186 @@ +kind: Template +apiVersion: v1 +metadata: + name: moon +objects: + + - kind: ResourceQuota + apiVersion: v1 + metadata: + name: max-moon-sessions + spec: + hard: + pods: ${MOON_PODS} + + - kind: Service + apiVersion: v1 + metadata: + name: moon + spec: + selector: + app: moon + ports: + - name: moon + protocol: TCP + port: 4444 + type: NodePort + + - kind: Service + apiVersion: v1 + metadata: + name: moon-api + spec: + selector: + app: moon-api + ports: + - name: moon-api + protocol: TCP + port: 8080 + type: NodePort + + - kind: Service + apiVersion: v1 + metadata: + name: moon-ui + spec: + selector: + app: moon-ui + ports: + - name: moon-ui + protocol: TCP + port: 8080 + type: NodePort + + - kind: DeploymentConfig + apiVersion: v1 + metadata: + name: moon + spec: + replicas: 1 + template: + metadata: + labels: + app: moon + spec: + containers: + - name: moon + image: ${MOON_IMAGE} + args: + - '-namespace' + - '${NAMESPACE}' + resources: + limits: + cpu: "1" + memory: "512Mi" + requests: + cpu: "0.25" + memory: "64Mi" + ports: + - containerPort: 4444 + volumeMounts: + - name: quota + mountPath: /quota + readOnly: true + - name: users + mountPath: /users + readOnly: true + volumes: + - name: quota + configMap: + name: quota + - name: users + secret: + secretName: users + + - kind: DeploymentConfig + apiVersion: v1 + metadata: + name: moon-api + spec: + replicas: 1 + template: + metadata: + labels: + app: moon-api + spec: + containers: + - name: moon-api + image: ${MOON_API_IMAGE} + args: + - '-namespace' + - '${NAMESPACE}' + resources: + limits: + cpu: "0.25" + memory: "128Mi" + requests: + cpu: "0.1" + memory: "64Mi" + ports: + - containerPort: 8080 + volumeMounts: + - name: quota + mountPath: /quota + volumes: + - name: quota + configMap: + name: quota + - name: users + secret: + secretName: users + + - kind: DeploymentConfig + apiVersion: v1 + metadata: + name: moon-ui + spec: + replicas: 1 + template: + metadata: + labels: + app: moon-ui + spec: + containers: + - name: moon-ui + args: + - '--selenoid-uri' + - 'http://moon-api:8080' + image: ${MOON_UI_IMAGE} + ports: + - containerPort: 8080 + protocol: TCP + resources: + limits: + cpu: 100m + memory: 64M + +parameters: +- name: NAMESPACE + displayName: Namespace + description: Namespace where the Moon is running + value: default + required: true + +- name: MOON_IMAGE + displayName: Moon docker image + description: Name of the image to be used. + value: aerokube/moon:latest-release + required: true + +- name: MOON_API_IMAGE + displayName: Moon-API docker image + description: Name of the image to be used. + value: aerokube/moon-api:latest-release + required: true + +- name: MOON_UI_IMAGE + displayName: Moon-UI docker image + description: Name of the image to be used. + value: aerokube/selenoid-ui:latest-release + required: true + +- name: MOON_PODS + displayName: Max moon pods in project + description: Specify max moon pods for project (4 free slots + Moon + Moon API + Moon UI = 7). + value: '7' + required: true \ No newline at end of file diff --git a/1.3.2/files/moon-sessions.yaml b/1.3.2/files/moon-sessions.yaml new file mode 100644 index 0000000..a424970 --- /dev/null +++ b/1.3.2/files/moon-sessions.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ResourceQuota +metadata: + name: max-moon-sessions +spec: + hard: + pods: "6" +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: moon-rbac +subjects: + - kind: ServiceAccount + name: default + namespace: default +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: rbac.authorization.k8s.io diff --git a/1.3.2/files/moon.yaml b/1.3.2/files/moon.yaml new file mode 100644 index 0000000..f21d953 --- /dev/null +++ b/1.3.2/files/moon.yaml @@ -0,0 +1,49 @@ +kind: Service +apiVersion: v1 +metadata: + name: moon +spec: + selector: + app: moon + ports: + - protocol: TCP + port: 4444 + type: NodePort +--- +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + name: moon +spec: + replicas: 1 + template: + metadata: + labels: + app: moon + spec: + containers: + - name: moon + image: aerokube/moon:1.3.2 + resources: + limits: + cpu: "1" + memory: "512Mi" + requests: + cpu: "0.25" + memory: "64Mi" + ports: + - containerPort: 4444 + volumeMounts: + - name: quota + mountPath: /quota + readOnly: true + - name: users + mountPath: /users + readOnly: true + volumes: + - name: quota + configMap: + name: quota + - name: users + secret: + secretName: users diff --git a/1.3.2/img/architecture.png b/1.3.2/img/architecture.png new file mode 100644 index 0000000..fc30688 Binary files /dev/null and b/1.3.2/img/architecture.png differ diff --git a/1.3.2/index.html b/1.3.2/index.html new file mode 100644 index 0000000..7e13b58 --- /dev/null +++ b/1.3.2/index.html @@ -0,0 +1,3658 @@ + + + + + + + + +Moon + + + + + + + +
+
+
+
+

This reference for version: 1.3.2

+
+
+

Moon is an enterprise version of Selenoid using Kubernetes to launch browsers.

+
+
+
+
+

1. Getting Started

+
+
+

1.1. Quick Start Guide

+
+
    +
  1. +

    Prerequisites:

    +
    +
      +
    • +

      Running Kubernetes cluster

      +
    • +
    • +

      kubectl client installed and pointing to the cluster

      +
    • +
    +
    +
  2. +
  3. +

    Clone an example configuration repository:

    +
    +
    +
    $ git clone https://github.com/aerokube/moon-deploy.git
    +$ cd moon-deploy
    +
    +
    +
  4. +
  5. +

    Run one command to start Moon and Moon API:

    +
    +
    +
    $ kubectl apply -f moon.yaml
    +
    +
    +
    +

    By default Moon is started in a separate namespace called moon so we append -n moon to the next commands.

    +
    +
  6. +
  7. +

    Wait for LoadBalancer IP to allocate:

    +
    +
    +
    $ kubectl get svc -n moon
    +NAME      TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                         AGE
    +moon      LoadBalancer   10.63.242.109   <pending>     4444:31894/TCP,8080:30625/TCP   17s
    +
    +
    +
    +

    It will look like this when finished:

    +
    +
    +
    +
    $ kubectl get svc -n moon
    +NAME      TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                         AGE
    +moon      LoadBalancer   10.63.242.109   104.154.161.58   4444:31894/TCP,8080:30625/TCP   1m
    +
    +
    +
    +

    Now you can optionally point a domain name to this IP address:

    +
    +
    +
    +
    $ host moon.example.com
    +moon.example.com has address 104.154.161.58
    +
    +
    +
  8. +
  9. +

    Run your tests against moon like you do with regular Selenium:

    +
    +
    +
    http://104.154.161.58:4444/wd/hub
    +
    +
    +
    + + + + + +
    + + +When running your tests for the first time for every browser version Kubernetes will download and cache requested browser image. This can take several minutes depending on your network connection. +
    +
    +
    +

    Same address using domain name:

    +
    +
    +
    +
    http://moon.example.com:4444/wd/hub
    +
    +
    +
  10. +
  11. +

    Moon web interface is available at:

    +
    +
    +
    http://104.154.161.58:8080/
    +
    +
    +
  12. +
+
+
+
+

1.2. Installing to Openshift

+
+
    +
  1. +

    Prerequisites:

    +
    +
      +
    • +

      Running Openshift cluster

      +
    • +
    • +

      oc client installed and pointing to the cluster

      +
    • +
    +
    +
  2. +
  3. +

    Example YAML and JSON files can be found in Example Configuration Files section.

    +
  4. +
  5. +

    Add view policy to default account so Moon could read project pod quota:

    +
    +
    +
    $ export PROJECT=default
    +$ oc policy add-role-to-user view system:serviceaccount:$PROJECT:default
    +
    +
    +
  6. +
  7. +

    Create users.htpasswd and respective secret:

    +
    +
    +
    $ htpasswd -Bbn test test-password >> users.htpasswd
    +$ oc create secret generic users --from-file=./users.htpasswd
    +
    +
    +
  8. +
  9. +

    Copy test quota to quota directory and initialize browsers configuration:

    +
    +
    +
    $ mkdir -p quota
    +$ touch quota/browsers.json # Add contents to file
    +$ oc create configmap quota --from-file=./quota
    +
    +
    +
  10. +
  11. +

    Start services using Openshift UI or the following command:

    +
    +
    +
    $ oc create -f moon-openshift.yaml -n $PROJECT
    +
    +
    +
  12. +
+
+
+
+

1.3. Required Permissions

+
+

Moon requires very limited set of permissions and should work with default Kubernetes settings. The following table summarizes what needs to be accessible.

+
+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 1. Required Moon Permissions

Permission

Purpose

To start and stop pods

Used to start pods with browsers

To start and stop services

Used to provide network connectivity to browser pods

To read data from config maps

Used to share various configuration data among Moon replicas: S3 configuration, custom images configuration and so on

To read data from secrets

Used to share S3 credentials among Moon replicas

To read resource quota information

Used to verify that Moon can run no more than total number of browser pods allowed by license

To create and update resource quota information

Optional. Used only in case when no resource quota was configured

To create and delete secrets

Optional. Used only in case when no resource quota was configured

+
+ + + + + +
+ + +All these permissions are normally enabled by default when running Moon and its browser pods in the same Kubernetes namespace. To configure a namespace for browser pods - use -namespace flag for Moon and Moon API. If you are starting Moon in one namespace and specify -namespace flag pointing to another namespace, then you may require additional Kubernetes permissions to be enabled. +
+
+
+
+

1.4. Cluster Architecture

+
+
Moon Cluster Architecture
+

architecture

+
+
+

Moon cluster consists of several important components:

+
+
+
    +
  1. +

    Kubernetes configuration map to store browser quota information and various runtime settings.

    +
  2. +
  3. +

    One or more moon application containers. Their main purpose is to start and stop browser containers. These replicas are usually exposed as Kubernetes service available on standard Selenium port 4444. You should run all the tests against this service.

    +
  4. +
  5. +

    One or more moon-api application containers. This API collects and returns various data about running browsers. moon-api is usually exposed as Kubernetes service available on HTTP port (e.g. 80 or 8080).

    +
  6. +
  7. +

    Running browser containers. Moon is using exactly the same containers as Selenoid.

    +
  8. +
+
+
+

Basic browser startup functionality is completely stateless and does not require any external database to be running.

+
+
+
+

1.5. Moon vs Selenoid

+
+

Moon takes all the best practices and features from Selenoid and adds many more:

+
+
+
    +
  1. +

    Unlimited automatic scalability. You always have enough browsers of any desired version available in the cluster. When running the cluster in cloud platforms such as Google Cloud you can adjust settings to automatically scale depending on current load. This allows to combine efficiency with competitive cost.

    +
  2. +
  3. +

    Completely stateless. Selenoid stores in memory information about currently running browser sessions. If for some reason its process crashes - then all running sessions are lost. Moon contrarily has no internal state and can be replicated across datacenters. Browser sessions remain alive even if one or more replicas go down.

    +
  4. +
  5. +

    Uniform load distribution. Load balancers like Ggr provide are using random load distribution across available browser hosts. This makes them inefficient when overall load is above 80% of cluster capacity. Moon delivers exactly uniform distribution working good even under 100% load.

    +
  6. +
  7. +

    Fully graceful. Any maintenance operations with the cluster do not interrupt running browser sessions. Every cluster component shuts down gracefully.

    +
  8. +
+
+
+
+
+
+

2. Configuration

+
+
+

2.1. Users List

+
+

Moon is a multi-user application allowing different users access different browser versions. A single htpasswd file is used to store users information. This file is saved to Kubernetes Secret and mounted to Moon container as a volume. A typical users file is a text file with user names and their encrypted passwords separated by colon:

+
+
+
+
$ cat users.htpasswd
+test:$apr1$.dZyHlKN$jdoZkin/kPviFNArx/cVL1 # User is test, password is encrypted
+alice:$apr1$mLYJAC4y$VYeJstWjWP/4iVlH/TNcD.
+bob:$apr1$gyqzbSpt$RBNcxrsQaolPZCQZW0VQW1
+
+
+
+

2.1.1. Updating Users List

+
+

To add or remove users:

+
+
+
    +
  1. +

    Modify users.htpasswd with htpasswd command:

    +
    +
    +
    $ htpasswd -Bbn new-user new-user-password >> users.htpasswd # Adding new user
    +$ htpasswd -Bb users.htpasswd some-user new-password # Updating password
    +$ htpasswd -D users.htpasswd test-user # Deleting existing user
    +
    +
    +
  2. +
  3. +

    Update users secret:

    +
    +
    +
    $ kubectl replace secret users --from-file=./users.htpasswd -n moon
    +
    +
    +
  4. +
  5. +

    Changes are applied immediately without Moon restart.

    +
  6. +
+
+
+
+
+

2.2. Browsers List

+
+

Moon is using a simple JSON-based configuration to store available browsers list. A typical browsers list file looks like the following:

+
+
+
Typical Browsers List File
+
+
{
+  "firefox": {                                      (1)
+    "default": "62.0",                              (2)
+    "versions": {                                   (3)
+      "62.0": {                                     (4)
+        "image": "selenoid/firefox:62.0",           (5)
+        "port": "4444",                             (6)
+        "path": "/wd/hub",                          (7)
+        "volumes": ["/from:/to", "/another:/test"], (8)
+        "resources": {                              (9)
+          "limits": {
+            "cpu": "2",
+            "memory": "2Gi"
+          },
+          "requests": {
+            "cpu": "200m",
+            "memory": "1Gi"
+          }
+        },
+        "privileged": true,                         (10)
+        "nodeSelector": {                           (11)
+          "node-type": "hardware"
+        },
+        "env": ["TZ=Europe/Moscow", "LANG=ru"],     (12)
+        "hosts": ["example.com:192.168.0.1"],       (13)
+      },
+      "60.0": {
+        //...
+      }
+    }
+  },
+  "chrome": {
+    //...
+  },
+  "opera": {
+    "default": "56.0",
+    "versions": {
+        //...
+    }
+  }
+}
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1Browser name
2Default browser version
3A list of available browser versions
4Version name
5Image name
6Port to proxy connections to. In the majority of cases should be 4444.
7Path relative to / where we request a new session, see below
8A list of volumes to mount to browser container
9Resource configuration for browser container (CPU and memory)
10Whether to run browser pod in privileged mode (default is false)
11Kubernetes node selector (allows to run pods on particular hosts only)
12Environment variables passed to browser container
13Custom /etc/hosts entries to be passed to browser container in hostname:ip format
+
+
+

2.2.1. Per-user Browser Lists

+
+

As you already know Moon is a multi-user application. For every user you need to create one file - <username>.json. For example for user alice from users.htpasswd you should create alice.json. All JSON files should be stored in the same directory specified by -quota-dir flag:

+
+
+
Per-user browser lists
+
+
\---quota
+|   ---- alice.json
+|   ---- browsers.json
+|   ---- bob.json
+|   ---- test.json
+
+
+
+

Such directory is then uploaded to Kubernetes ConfigMap and mounted to Moon container as a volume.

+
+
+
+

2.2.2. Guest Quota

+
+

In some cases you may need anonymous Selenium access - without username and password. In terms of Moon this is called guest quota and is configured with -guest-user flag (default value is browsers). Any browser versions specified in <guest-user>.json file will be available without username and password:

+
+
+
Guest quota file name
+
+
-guest-user browsers ====> browsers.json # This is the default
+-guest-user guest-user ====> guest-user.json
+
+
+
+
+

2.2.3. Updating Browsers List

+
+

To add or remove browsers:

+
+
+
    +
  1. +

    Having configuration files stored in quota directory apply desired modifications.

    +
  2. +
  3. +

    Update quota ConfigMap using contents of quota directory:

    +
    +
    +
    $ kubectl replace configmap quota --from-file=quota -n moon
    +
    +
    +
  4. +
  5. +

    Changes are applied immediately without Moon restart. All running user sessions will continue to work without any interruption.

    +
  6. +
+
+
+
+
+

2.3. Configuration File

+
+

Moon stores all advanced configuration options (e.g. S3 settings) in a special JSON file called service.json:

+
+
+
Typical service.json file
+
+
{
+  "s3": {                                          (1)
+    "endpoint": "https://storage.googleapis.com",  (2)
+    "bucketName": "moon-test",                     (3)
+    "version": "S3v2"                              (4)
+  },
+  "images": {                                      (5)
+    "logger": {                                    (6)
+      "image": "my-reg.com/moon/logger:1.2.0",     (7)
+      "cpu": "0.3",                                (8)
+      "mem": "1024Mi"                              (9)
+    }
+  }
+}
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1S3 configuration section
2S3 endpoint URL
3S3 bucket name
4S3 signature version (should be S3v2 or S3v4)
5Custom Moon system images section (to use Moon with private Docker registries)
6Custom Moon image definition (one of logger, defender, videoRecorder)
7Custom Moon image reference
8Custom Moon image CPU limit
9Custom Moon image memory limit
+
+
+

service.json is mounted to Moon container as a regular file using Kubernetes config map. Path to configuration file is specified with -config-file Moon flag. Any changes to configuration file are applied immediately - no need to restart Moon.

+
+
+
Adding service.json file to Moon
+
+
apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: config
+  namespace: moon
+data:
+  service.json: |
+    {
+      "s3": {
+        "endpoint": "https://storage.googleapis.com",
+        "bucketName": "moon-test",
+        "version": "S3v2"
+      }
+    }
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+  name: moon
+  namespace: moon
+spec:
+  template:
+    metadata:
+      labels:
+        app: moon
+    spec:
+      containers:
+      - name: moon
+        image: aerokube/moon:latest-release
+        args: ["-config-file", "/config/service.json"]
+        volumeMounts:
+        - name: config
+          mountPath: /config
+          readOnly: true
+    volumes:
+      - name: config
+        configMap:
+          name: config
+
+
+
+
+

2.4. Credentials Secret

+
+

Moon reads all credentials (e.g. S3 keys) from an optional Kubernetes secret called credentials. This secret is mounted to Moon container as a regular directory with files corresponding to different. Path to credentials directory is specified with -credentials-file Moon flag. Any changes to credentials secret are applied immediately - no need to restart Moon.

+
+
+
Adding credentials secret to Moon
+
+
apiVersion: v1
+kind: Secret
+metadata:
+  name: credentials
+  namespace: moon
+stringData:
+  s3.accessKey: "access-key-value"
+  s3.secretKey: "secret-key-value"
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+  name: moon
+  namespace: moon
+spec:
+  template:
+    metadata:
+      labels:
+        app: moon
+    spec:
+      containers:
+      - name: moon
+        image: aerokube/moon:latest-release
+        args: ["-credentials-dir", "/credentials"]
+        volumeMounts:
+        - name: credentials
+          mountPath: /credentials
+          readOnly: true
+    volumes:
+    - name: credentials
+      secret:
+        secretName: credentials
+
+
+
+

The following keys are supported:

+
+ + ++++ + + + + + + + + + + + + + + + + +
Table 2. Supported Credentials Secret Keys
KeyMeaning

s3.accessKey

S3 access key value

s3.secretKey

S3 secret key value

+
+
+

2.5. Installing License

+
+ + + + + +
+ + +According to license agreement you can use up to 4 parallel sessions without a license. If you wish to have more parallel sessions - order a license and follow this section steps to install the license. +
+
+
+
    +
  1. +

    To install a license you should have a license key file. A typical license file looks like this:

    +
    +
    +
    $ cat license.key
    +Ti90a3ljSWpvV3hicU5ZY3U3ZVNMUzdzalVjU29nSVU2a3lmWDdENmhOSEs4SFJVVE5LNEpKL2oxRGhWTnRhZVBEQmx5cm1SM0dFWlVpbGIwOWhBSUpvWmlQMnNtYmtoZVRDbnJ3UTlIV3grMUMzaXFJalU3L0NIZDJuSzN3QUpIS0lyV2VoVjlRVUh5NzNCMFg0NEV5KzFSVXg1elhvaC9RUkNjTlBIOHR4WWtrRFBmTFhxYTFESlI0aXNObGtobWpXY2VJNVdna1lsWHFFOUp0OUxValZPN05hb2pCcHJzY0pvZjBrZys2YkhWUDR3cUJvYVFoSFJTYzMzZzNRSTkrWVd4dlZCeExmdTVxM2k2ZnluMDRHSEhGc21Fd2owVHdVa1Z3MmI5Z2FyVXlaVFF4RDdCRjVSVjBmSUVrU1pEQ0ZQdmIvMHZoKythY1V4OVRrR2FBREZzbWR3dExxRlU4NHF3MzBVdE5nTGhnNWYxRXRCQ215R1BHR0wyK2NpR0RDZDBTSXg4K1RsRGNWVzUyVVY4MUt6bkdOanJhTklOeXVtYjVPVXF6aVVpdmJZeVJNVVBSMWF3NUJRVGJDaHVycWVVdGtMMWFRZDgwOCtoWGRxODFOakxRNEJlVENNQTdPL2FneHBTUE1nL0J2QmVQKy84ZGhJeXd5Y0lxQVJhVWxocUdmUko2K05tbkFYV0hzZ2RjTng1dUVHU0w5VWF5TU1rR3RkZEZKQ1FiWmF0RnJMaDFHbHhKTndBRHFWcXIvQ0oxSzBQL2p6K2NFSWpsSG82TktvM3pudVFlanhYT2tGU1p1bWZrS1krZmF3VkVRZWlvcFlmZFk0TU9tc3U5TThsbng3T2VXQXZmOTFUQ2w1NUhBK1ZsQTMzN3VFOG1WV3ZlS0E1Tlk9O2V5SnNhV05sYm5ObFpTSTZJa0ZqYldVZ1RFeERJaXdpY0hKdlpIVmpkQ0k2SWsxdmIyNGlMQ0p0WVhoVFpYTnphVzl1Y3lJNk1qQXNJblJ2SWpveE5UTTRNelV5TURBd2ZRPT0=
    +
    +
    +
    +

    Moon container is expecting to find license key file in the path specified by -license-file parameter. You need to mount license key file as a volume to every Moon container

    +
    +
  2. +
  3. +

    Having a license key file - create a Kubernetes secret:

    +
    +
    +
    $ kubectl create secret generic license-key --from-file /path/to/license.key -n moon
    +
    +
    +
    +

    If you prefer YAML - this will look like:

    +
    +
    +
    Creating a secret for license key
    +
    +
    apiVersion: v1
    +kind: Secret
    +metadata:
    +  name: license-key
    +  namespace: moon
    +stringData:
    +  license.key: Ti90a3ljSWpvV3hicU5ZY3U3ZVNMUzdzalVjU29nSVU2a3lmWDdENmhOSEs4SFJVVE5LNEpKL2oxRGhWTnRhZVBEQmx5cm1SM0dFWlVpbGIwOWhBSUpvWmlQMnNtYmtoZVRDbnJ3UTlIV3grMUMzaXFJalU3L0NIZDJuSzN3QUpIS0lyV2VoVjlRVUh5NzNCMFg0NEV5KzFSVXg1elhvaC9RUkNjTlBIOHR4WWtrRFBmTFhxYTFESlI0aXNObGtobWpXY2VJNVdna1lsWHFFOUp0OUxValZPN05hb2pCcHJzY0pvZjBrZys2YkhWUDR3cUJvYVFoSFJTYzMzZzNRSTkrWVd4dlZCeExmdTVxM2k2ZnluMDRHSEhGc21Fd2owVHdVa1Z3MmI5Z2FyVXlaVFF4RDdCRjVSVjBmSUVrU1pEQ0ZQdmIvMHZoKythY1V4OVRrR2FBREZzbWR3dExxRlU4NHF3MzBVdE5nTGhnNWYxRXRCQ215R1BHR0wyK2NpR0RDZDBTSXg4K1RsRGNWVzUyVVY4MUt6bkdOanJhTklOeXVtYjVPVXF6aVVpdmJZeVJNVVBSMWF3NUJRVGJDaHVycWVVdGtMMWFRZDgwOCtoWGRxODFOakxRNEJlVENNQTdPL2FneHBTUE1nL0J2QmVQKy84ZGhJeXd5Y0lxQVJhVWxocUdmUko2K05tbkFYV0hzZ2RjTng1dUVHU0w5VWF5TU1rR3RkZEZKQ1FiWmF0RnJMaDFHbHhKTndBRHFWcXIvQ0oxSzBQL2p6K2NFSWpsSG82TktvM3pudVFlanhYT2tGU1p1bWZrS1krZmF3VkVRZWlvcFlmZFk0TU9tc3U5TThsbng3T2VXQXZmOTFUQ2w1NUhBK1ZsQTMzN3VFOG1WV3ZlS0E1Tlk9O2V5SnNhV05sYm5ObFpTSTZJa0ZqYldVZ1RFeERJaXdpY0hKdlpIVmpkQ0k2SWsxdmIyNGlMQ0p0WVhoVFpYTnphVzl1Y3lJNk1qQXNJblJ2SWpveE5UTTRNelV5TURBd2ZRPT0=
    +
    +
    +
  4. +
  5. +

    When starting Moon - mount this secret as a volume and point -license-file to mounted file:

    +
    +
    Starting Moon with license key
    +
    +
    apiVersion: apps/v1beta1
    +kind: Deployment
    +metadata:
    +  name: moon
    +  namespace: moon
    +spec:
    +  replicas: 3
    +  template:
    +    metadata:
    +      labels:
    +        app: moon
    +    spec:
    +      containers:
    +      - name: moon
    +        image: aerokube/moon:latest-release
    +        args: ["-license-file", "/license/license.key"] # Pointing to license key file
    +        resources:
    +            # Resources here
    +        ports:
    +            # Ports here
    +        volumeMounts:
    +        # Other mounts here
    +        - name: license-key # Mounting volume with license key
    +          mountPath: /license
    +          readOnly: true
    +    volumes:
    +    # Other volumes here
    +    - name: license-key # Creating volume from secret
    +      secret:
    +        secretName: license-key
    +
    +
    +
  6. +
+
+
+
+

2.6. Advanced Configuration

+
+

2.6.1. Uploading Files to S3

+
+

You can configure Moon to send sessions logs and recorded video files to S3-compatible storage. Such type of storage is supported by AWS, Google Cloud, Microsoft Azure, Digital Ocean and many other cloud providers. To deploy a private S3-compatible storage you can use Minio. To enable S3 support in Moon:

+
+
+
    +
  1. +

    Create an S3 bucket. In this example bucket name is moon-test. You will get an access key and a secret key for the bucket. Also you need to know supported S3 protocol version (usually specified in documentation).

    +
  2. +
  3. +

    Create a service.json file with the following contents:

    +
    +
    +
    $ cat service.json
    +{
    +  "s3": {
    +    "endpoint": "https://storage.googleapis.com",
    +    "bucketName": "moon-test",
    +    "version": "S3v2"
    +  }
    +}
    +
    +
    +
  4. +
  5. +

    Save service.json to a Kubernetes config map, mount it as a file to Moon container and then specify path to the file using -config-file flag as shown in Configuration File section.

    +
  6. +
  7. +

    Create a credentials.json file to store S3 keys:

    +
    +
    +
    $ cat service.json
    +{
    +  "s3": {
    +    "accessKey": "access-key-value",
    +    "secretKey": "secret-key-value"
    +  }
    +}
    +
    +
    +
  8. +
  9. +

    Save credentials.json to a Kubernetes secret, mount it as a file to Moon container and then specify path to the file using -credentials-file flag as shown in [Credentials File] section.

    +
  10. +
  11. +

    When you update a config map with service.json or a secret with credentials.json - settings are applied immediately without Moon restart.

    +
  12. +
+
+
+
+

2.6.2. Using Custom Moon Images

+
+

By default Moon downloads some service images (aerokube/defender, aerokube/logger and so on) from public Docker registry. If in your environment due to security restrictions Docker images can only be downloaded from private registry you need to provide image names to Moon. To do this:

+
+
+
    +
  1. +

    Copy the following public images to your registry:

    +
    +
    +
    aerokube/moon
    +aerokube/moon-api
    +aerokube/moon-video-recorder
    +aerokube/defender
    +aerokube/logger
    +
    +
    +
  2. +
  3. +

    Create a service.json file with the following contents:

    +
    +
    +
    $ cat service.json
    +{
    +  "images": {
    +    "videoRecorder": {
    +        "image": "my-registry.example.com/moon/video-recorder:latest-release"
    +    },
    +    "defender": {
    +        "image": "my-registry.example.com/moon/defender:latest-release"
    +    },
    +    "logger": {
    +        "image": "my-registry.example.com/moon/logger:latest-release"
    +    }
    +  }
    +}
    +
    +
    +
    +

    If you already have S3 configuration in service.json file - just append new images key to it.

    +
    +
    +

    You can optionally adjust CPU and memory limits for each image as follows:

    +
    +
    +
    Adjusting memory and CPU limits for system images
    +
    +
    {
    +  "images": {
    +    "logger": {
    +      "image": "my-registry.example.com/moon/video-recorder:latest-release",
    +      "cpu": "0.3",
    +      "mem": "1024Mi"
    +    }
    +  }
    +}
    +
    +
    +
  4. +
  5. +

    Save service.json to a Kubernetes config map, mount it as a file to Moon container and then specify path to the file using -config-file flag as shown in Configuration File section.

    +
  6. +
  7. +

    When you update a config map with service.json - settings are applied immediately without Moon restart.

    +
  8. +
+
+
+
+

2.6.3. Adjusting Timeouts

+
+

Sometimes things go wrong: user can unexpectedly disconnect or browser session starts longer than needed. This can lead to overall cluster degradation because of broken browser pods occupying all available hardware. To prevent such cases Moon automatically detects and closes suspicious browser sessions. Several flags allow to adjust timeout settings:

+
+ + ++++++ + + + + + + + + + + + + + + + + + + + + + + +
Table 3. Available Timeout Flags
FlagDefault ValueMeaningNotes

-timeout

1 minute

Maximum browser session idle time - measured as maximum time between separate HTTP requests corresponding to a running session.

When this timeout expires - session is automatically closed. You may need to increase this timeout when tested application pages load too slowly.

-session-attempt-timeout

10 minutes

Maximum time to start browser pod.

This time includes Kubernetes scheduling time and browser image download duration.

+
+
+

2.6.4. Adjusting Resources Consumption

+
+ + + + + +
+ + +Flags and fields described in this section apply to browser container consumption only. Other system containers started in browser pod have reasonable fixed values assigned. +
+
+
+

Moon has reasonable defaults for resources consumed by every browser pod. Sometimes you may need to override these settings. To override resource settings globally for every browser image use one of the following flags:

+
+ + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 4. Resources Consumption Flags
FlagDefault ValueMeaning

-cpu-limit

1

Hard CPU limit for browser container (no more than this limit is given)

-cpu-request

1

Soft (guaranteed) CPU limit for browser container

-memory-limit

1Gi

Hard memory limit for browser container

-memory-request

512Mi

Soft memory limit for browser container

+
+

You can also override the same values for every browser image in browsers list file:

+
+
+
Overriding Resources in Browsers List File
+
+
{
+  "firefox": {
+    "default": "62.0",
+    "versions": {
+      "62.0":
+        "image": "selenoid/firefox:62.0",
+        "port": "4444",
+        "path": "/wd/hub",
+        "resources": {                              (1)
+          "limits": {                               (2)
+            "cpu": "2",                             (3)
+            "memory": "2Gi"                         (4)
+          },
+          "requests": {                             (5)
+            "cpu": "200m",                          (6)
+            "memory": "1Gi"                         (7)
+          }
+        }
+      }
+    }
+  }
+}
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1Resources definition section
2Limits definition section
3CPU limit field
4Memory limit field
5Requests definition section
6CPU request field
7Memory request field
+
+
+
+

2.6.5. Running Browser Pods in Privileged Mode

+
+

In some cases like running Android emulators browser container should be run in privileged mode. This setting can be applied separately to each browser version in browsers list file as follows:

+
+
+
Starting Container in Privileged Mode
+
+
{
+  "firefox": {
+    "default": "62.0",
+    "versions": {
+      "62.0":
+        "image": "selenoid/firefox:62.0",
+        "port": "4444",
+        "path": "/wd/hub",
+        "privileged": true                  (1)
+      }
+    }
+  }
+}
+
+
+
+ + + + + +
1Launch container in privileged mode
+
+
+
+

2.6.6. Using Node Selectors

+
+

Sometimes you may need to run browser pods on particular Kubernetes nodes (i.e. hardware hosts) only. Kubernetes allows to do this by specifying so called node selectors. To provide such selector to Moon browser pods update browsers list as shown below:

+
+
+
Adding Node Selectors
+
+
{
+  "firefox": {
+    "default": "62.0",
+    "versions": {
+      "62.0":
+        "image": "selenoid/firefox:62.0",
+        "port": "4444",
+        "path": "/wd/hub",
+        "nodeSelector": {                    (1)
+          "node-type": "hardware"
+        },
+      }
+    }
+  }
+}
+
+
+
+ + + + + +
1Node selector for this browser version
+
+
+
+
+

2.7. Log Files

+
+

Every log line contains:

+
+ + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 5. Log entry contents
FieldExampleNotes

Time

2017/11/01 19:12:42

-

Status

[SESSION_ATTEMPTED]

See table below for complete list of statuses.

Additional fields

[firefox-45.0]

One or more sections showing additional information such as browser name, user name, IP address or error message

Attempt number

[1]

For SESSION_ATTEMPTED or SESSION_CREATED entries means current attempt number. For SESSION_CREATED entries means total number of attempts to create this session.

Duration

[4.15s]

For some log entries this field shows how much time operation took

+
+

The following statuses are available:

+
+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 6. Log entry statuses
StatusDescription

AWAITING_SERVICE

Waiting for Kubernetes service to start

BAD_REQUEST

Failed to process user request

BAD_RESOURCES

User incorrectly configured browser container resources

BAD_SCREEN_RESOLUTION

User requested to set wrong custom screen resolution

BAD_TIMEZONE

User requested to set wrong custom time zone inside container

BAD_TIMEOUT

User requested to set wrong session timeout

BAD_VIDEO_FRAME_RATE

User requested to capture video with wrong frame rate

BAD_VIDEO_SCREEN_SIZE

User requested to capture video with wrong screen size

CLIENT_DISCONNECTED

User disconnected and session was interrupted

CREATING_POD

Starting to create pod with browser

CREATING_SERVICE

Starting to create service for browser session

DELETING_POD

Starting to delete pod with browser

DELETING_SERVICE

Starting to delete service for browser session

DELETING_SESSION

Received request to delete browser session

EMPTY_REQUEST

Received empty request from user

FAILED_TO_CREATE_POD

Failed to create browser pod

FAILED_TO_CREATE_SERVICE

Failed to create browser service

FAILED_TO_DELETE_POD

Failed to delete browser pod

FAILED_TO_DELETE_SERVICE

Failed to delete browser service

FAILED_TO_DELETE_SESSION

Failed to delete browser session

FAILED_TO_GET_LOGS

Failed to get session logs

FORBIDDEN_TO_CREATE_POD

Kubernetes return forbidden status when creating pod

INIT

Service initialization messages

LOGS

Requested session logs

LOGS_CLIENT_DISCONNECTED

Client disconnected while streaming session logs

MALFORMED_VOLUME

Moon skipped malformed volume specification from browsers.json

POD_CREATED

Browser pod created

POD_DELETED

Browser pod deleted

PROXYING

Proxying requests to specified URL

PROXY_ERROR

Failed to proxy requests to specified URL

SERVER_ERROR

Failed to create pod or service due to internal server error (probably a bug)

SERVICE_CREATED

Browser service created

SERVICE_DELETED

Browser service deleted

SERVICE_IS_UP

Browser service successfully started

SESSION_CREATED

Browser session successfully created

SESSION_DELETED

Session successfully deleted

SESSION_FAILED

Failed to create new session

SESSION_TIMED_OUT

Existing session timed out

SESSION_NOT_FOUND

Received request with empty session ID

SHUTTING_DOWN

Shutting down the service

STATUS_ERROR

Failed to refresh Moon status

STATUS_REQUEST

Received Moon status request

STATUS_REQUEST_ERROR

Failed to return Moon status

UNSUPPORTED_BROWSER

User requested unsupported browser

USER_NOT_FOUND

Trying to request session with unknown user

VNC_CLIENT_DISCONNECTED

User disconnected while proxying VNC traffic

VNC_ERROR

An error occurred while proxying VNC traffic

VNC_SESSION

User requested VNC session

VNC_SESSION_CLOSED

User closed VNC session

+
+
+

2.8. CLI Flags

+
+

These flags should be specified in Kubernetes YAML files when starting the cluster.

+
+
+

The following flags are supported by moon:

+
+
+
+
-config-file string
+    optional configuration file (default "config/service.json")
+-cpu-limit string
+    browser container cpu limit (default "1")
+-cpu-request string
+    browser container cpu request (default "0.5")
+-credentials-dir string
+    directory where credentials are mounted (default "credentials")
+-grace-period duration
+    graceful shutdown (default 30s)
+-guest-user string
+    guest quota user name (default "browsers")
+-license-file string
+    path to license file (default "license/license.key")
+-listen string
+    address to bind (default ":4444")
+-memory-limit string
+    browser container memory limit (default "1Gi")
+-memory-request string
+    browser container memory request (default "512Mi")
+-namespace string
+    namespace
+-quota-dir string
+    quota directory (default "quota")
+-session-attempt-timeout duration
+    new session attempt timeout (default 30m0s)
+-timeout duration
+    override session timeout (default 1m0s)
+-users-file string
+    path to users file (default "users/users.htpasswd")
+-version
+    show version and exit
+
+
+
+
+
+
+

3. Advanced Features

+
+
+

3.1. Special Capabilities

+
+

Moon supports a set of custom capabilities. You can pass them in tests to enable or disable some features.

+
+
+

3.1.1. Live Browser Screen: enableVNC

+
+

Moon supports showing browser screen during test execution. To see browser screen add capability:

+
+
+
Type: boolean
+
+
enableVNC: true
+
+
+
+

Browser screen will be shown in Selenoid UI.

+
+
+
+

3.1.2. Custom Screen Resolution: screenResolution

+
+

Moon allows you to set custom screen resolution in containers being run:

+
+
+
Type: string, format: <width>x<height>
+
+
screenResolution: "1280x1024"
+
+
+
+

You can optionally add colors depth:

+
+
+
Type: string, format: <width>x<height>x<colors-depth>
+
+
screenResolution: "1280x1024x24"
+
+
+
+ + + + + +
+ + +
+

This capability sets only screen resolution - not browser window size. +Most of browsers have some default window size value this is why your screenshot size can be smaller than screen resolution specified in capability. +You should manually resize window to desired width and height or use Selenium maximize operation.

+
+
+
+
+
+

3.1.3. Video Recording: enableVideo, videoName, videoScreenSize, videoFrameRate, videoCodec

+
+

To enable video recording for session, add:

+
+
+
Type: boolean
+
+
enableVideo: true
+
+
+
+
    +
  • +

    By default saved video files are named <session-id>.mp4 where <session-id> is a unique identifier of Selenium session. +To provide custom video name specify:

    +
    +
    Type: string
    +
    +
    videoName: "my-cool-video.mp4"
    +
    +
    +
    + + + + + +
    + + +It is important to add mp4 file extension. +
    +
    +
  • +
  • +

    By default the entire screen picture is being recorded. +Specifying screenResolution capability changes recorded video size (width and height) accordingly. +You can override video screen size by passing a capability. In case of videoScreenSize +resolution is less than actual, screen on video will be trimmed starting from top-left corner:

    +
    +
    Type: string
    +
    +
    videoScreenSize: "1024x768"
    +
    +
    +
  • +
  • +

    Default video frame rate is 12 frames per second. Specifying videoFrameRate capability changes this value:

    +
    +
    Type: int
    +
    +
    videoFrameRate: 24
    +
    +
    +
  • +
  • +

    By default Moon is using libx264 codec for video output. If this codec is consuming too much CPU, you can change it using videoCodec capability:

    +
    +
    Type: string
    +
    +
    videoCodec: "mpeg4"
    +
    +
    +
  • +
+
+
+
+

3.1.4. Custom Test Name: name

+
+

For debugging purposes it is often useful to give a distinct name to every test case. You can set test case name by passing the following capability:

+
+
+
Type: string
+
+
name: "myCoolTestName"
+
+
+
+

The main application of this capability - is debugging tests in the UI which is showing specified name for every running session.

+
+
+
+

3.1.5. Per-session Time Zone: timeZone

+
+

Some tests require particular time zone to be set in operating system.

+
+
+
Type: string
+
+
timeZone: "Europe/Moscow"
+
+
+
+

You can find most of available time zones here. +Without this capability launched browser containers will have Moon timezone.

+
+
+
+

3.1.6. Per-session Environment Variables: env

+
+

Sometimes you may want to set some environment variables for every test case (for example to test with different default locales). To achieve this pass one more capability:

+
+
+
Type: array, format: <key>=<value>
+
+
env: ["LANG=ru_RU.UTF-8", "LANGUAGE=ru:en", "LC_ALL=ru_RU.UTF-8"]
+
+
+
+

Environment variables from this capability are appended to variables from configuration file.

+
+
+
+

3.1.7. Hosts Entries: hostsEntries

+
+

Although you can configure a separate list of /etc/hosts entries for every browser image in Browsers List sometimes you may need to add more entries for particular test cases. This can be easily achieved with:

+
+
+
Type: array, format: <hostname>:<ip-address>
+
+
hostsEntries: ["example.com:192.168.0.1", "test.com:192.168.0.2"]
+
+
+
+

Entries from this capability will be override /etc/hosts entries from browsers list file.

+
+
+
+

3.1.8. Custom Session Timeout: sessionTimeout

+
+

Sometimes you may want to change idle timeout for selected browser session. To achieve this - pass the following capability:

+
+
+
Type: int
+
+
sessionTimeout: 1m30s
+
+
+
+

Timeout is always specified in Golang duration format, e.g. 30s or 2m or 1h and so on.

+
+
+
+

3.1.9. Specifying Capabilities via Protocol Extensions

+
+

Some Selenium clients allow passing only a limited number of capabilities specified in WebDriver specification. For such cases Moon supports reading capabilities using WebDriver protocol extensions feature. The following two examples deliver the same result. Usually capabilities are passed like this:

+
+
+
Passing Capabilities as Usually
+
+
{"browserName": "firefox", "version": "62.0", "screenResolution": "1280x1024x24"}
+
+
+
+

Moon is using moon:options key to read protocol extension capabilities:

+
+
+
Passing Capabilities using Protocol Extensions
+
+
{"browserName": "firefox", "version": "62.0", "moon:options": {"screenResolution": "1280x1024x24"}}
+
+
+
+
+
+

3.2. Accessing Files Downloaded with Browser

+
+ + + + + +
+ + +Files are accessible only when browser session is running. +
+
+
+

Your tests may need to download files with browsers. To analyze these files a common requirement is then to somehow extract downloaded files from browser containers. Moon provides a /download API dramatically simplifying downloading such files. To work with it:

+
+
+
    +
  1. +

    Start a new session, for example with ID firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840.

    +
  2. +
  3. +

    In tests code save all files to ~/Downloads directory.

    +
  4. +
  5. +

    Access all downloaded files using an URL:

    +
    +
    +
    http://moon-host.example.com:4444/download/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/myfile.txt
    +
    +
    +
  6. +
  7. +

    Close the session

    +
  8. +
+
+
+
+

3.3. Accessing Clipboard

+
+ + + + + +
+ + +Clipboard is accessible only when browser session is running. +
+
+
+

Sometimes you may need to interact with the clipboard to check that your application copy-paste feature works. Moon has a dedicated API to interact with the clipboard. To use it:

+
+
+
    +
  1. +

    Start a new session, for example with ID firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840.

    +
  2. +
  3. +

    To get clipboard value send the following HTTP request:

    +
    +
    +
    $ curl http://moon-host.example.com:4444/clipboard/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840
    +
    +some-clipboard-value
    +
    +
    +
  4. +
  5. +

    To update clipboard value:

    +
    +
    +
    $ curl -X POST --data 'some-clipboard-value' http://moon-host.example.com:4444/clipboard/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840
    +
    +
    +
  6. +
+
+
+
+
+
+

4. License Agreement

+
+
+

Last updated January 5th, 2018. Replaces the prior version in its entirety.

+
+
+

This is a legal agreement. By downloading, installing, copying, saving on Customer’s computer, or otherwise using Aerokube software, support or products Customer becomes a party to this Agreement and Customer consents to be bound by all the terms and conditions set forth below.

+
+
+
    +
  1. +

    Parties

    +
    +
      +
    1. +

      "Aerokube", "Licensor" or "We" means Aerokube OÜ, having its principal place of business at Narva mnt 7-123, Tallinn city, Harju county, 10117, Estonia, registered in the Commercial Register of Estonia, registry code: 12345678.

      +
    2. +
    3. +

      "Customer", "Licensee" or "You" means the sole proprietor or legal entity specified in the Subscription Confirmation. For legal entities, "Customer" includes any entity which controls, is controlled by, or is under common control with Customer. For the purposes of this definition, "control" means one of the following:

      +
      +
        +
      1. +

        The power, directly or indirectly, to direct or manage such entity, whether by contract or otherwise.

        +
      2. +
      3. +

        Ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity.

        +
      4. +
      +
      +
    4. +
    +
    +
  2. +
  3. +

    Definitions

    +
    +
      +
    1. +

      "Agreement" means this License Agreement.

      +
    2. +
    3. +

      "Product" means any generally available Licensor’s software product identified by Licensor as a software developer tool. For the avoidance of doubt, the Product is not produced to the specifications of Customer nor customized through modification or personalization, is intended for mass distribution, and no software code will be provided to Customer.

      +
    4. +
    5. +

      "User" means any employee, independent contractor or other personnel obtaining access to the Product(s) from Customer.

      +
    6. +
    7. +

      "Number of Concurrent Sessions" means maximum number of software testing processes being run using the Product in parallel. This can be for example browsers executing User’s tests.

      +
    8. +
    9. +

      "License Key" means a unique key-code that enables a Licensee to use the Product by unlocking the fixed Number of Concurrent Sessions. Only Licensor and/or its representatives are permitted to produce License Keys for the Product.

      +
    10. +
    11. +

      "Subscription" means an arrangement for making use of the Product of periodic nature on a prepayment plan. For the purpose of clarity, Subscription includes the subscription term, Products provided to Customer, subscription fees, payment schedules and fixed number of License Keys.

      +
    12. +
    13. +

      "Product Evaluation" means using the Product without a valid License Key.

      +
    14. +
    15. +

      "Subscription Confirmation" means an email confirming Customer’s rights to access and use Products, including total Number of Concurrent Sessions.

      +
    16. +
    17. +

      "Product Installation" means a Product copy running on Customer’s computer device, hardware server or virtual machine.

      +
    18. +
    19. +

      "Product Version" means a release, update, or upgrade of a particular Product that is not identified by Licensor as being made for the purpose of fixing software bugs.

      +
    20. +
    21. +

      "Bug Fix Update" for a particular Product Version means a software update or release that is specifically identified by Licensor as a bug fix for that Product Version.

      +
    22. +
    23. +

      "Fallback Date" means the date that was 12 months prior to the date of expiration of the Subscription.

      +
    24. +
    25. +

      "Fallback Version" means the most recent Product Version that Licensor made available for public purchase prior to the Fallback Date, along with any Bug Fix Updates for that Product Version. For the purpose of clarity, Fallback Version does not include any Product updates or upgrades other than Bug Fix Updates that Customer may have used in the period between the Fallback Date and the date of expiration of the Subscription.

      +
    26. +
    27. +

      "E-mail Support" means a form of customer support provided by the Licensor. At the time of writing, the corresponding e-mail address is support@aerokube.com; should the address be changed, the new address will be referred to on the Licensor’s web site.

      +
    28. +
    29. +

      "Instant Messaging Support" means a form of customer support provided by the Licensor. At the time of writing, the corresponding address to support channel is https://t.me/aerokube_moon; should the address be changed, the new address will be referred to on the Licensor’s web site.

      +
    30. +
    31. +

      "Affiliate" means any entity belonging to the same group as the Licensor.

      +
    32. +
    +
    +
  4. +
  5. +

    How this Agreement Works

    +
    +
      +
    1. +

      Entire Agreement. This Agreement, including the Third-Party Software license terms, constitutes the entire agreement between the parties concerning its subject matter and supersedes any prior agreements between Customer and Licensor regarding Customer’s use of any Products. No purchase order, other ordering document or any handwritten or typewritten text which purports to modify or supplement the printed text of this Agreement or any schedule will add to or vary the terms of this Agreement unless signed by both Customer and Licensor.

      +
    2. +
    3. +

      Reservation of Rights. Aerokube reserves the right at any time to cease the support of the Product and to alter prices, features, specifications, capabilities, functions, terms of use, release dates, general availability or other characteristics of the Product.

      +
    4. +
    5. +

      Changes to this Agreement. We may update or modify this Agreement from time to time, including any referenced policies and other documents. If a revision meaningfully reduces Customer’s rights, we will use reasonable efforts to notify Customer. If we modify this Agreement, the modified version of the Agreement will be effective from the start of the next Subscription term. In this case, if Customer objects to the updated Agreement terms, as Customer’s exclusive remedy, Customer may cancel the Subscription. Customer may be required to click through the updated Agreement to show its acceptance. For the avoidance of doubt, each Subscription Confirmation is subject to the version of the Agreement in effect on the Subscription Confirmation date.

      +
    6. +
    7. +

      Opportunity to Review. Customer hereby declares that Customer has had sufficient opportunity to review this Agreement, understand the content of all of its clauses, negotiate its terms, and seek independent professional legal advice in that respect before entering into it. Consequently, any statutory "form contract" ("adhesion contract") regulations shall not be applicable to this Agreement.

      +
    8. +
    9. +

      Severability. If a particular term of this Agreement is not enforceable, the unenforceability of that term will not affect any other terms of this Agreement.

      +
    10. +
    11. +

      Headings. Headings and titles are for convenience only and do not affect the interpretation of this Agreement.

      +
    12. +
    13. +

      No Waiver. Our failure to enforce or exercise any part of this Agreement is not a waiver of that section.

      +
    14. +
    15. +

      Notice. Aerokube may deliver any notice to Customer via electronic mail to an email address provided by Customer, registered mail, personal delivery or renowned express courier (such as DHL, FedEx or UPS). Any such notice will be deemed to be effective:

      +
      +
        +
      1. +

        On the day the notice is sent to Customer via email.

        +
      2. +
      3. +

        Upon personal delivery.

        +
      4. +
      5. +

        One (1) day after deposit with an express courier or five (5) days after deposit in the mail, whichever occurs first.

        +
      6. +
      +
      +
    16. +
    17. +

      Governing Law. This Agreement will be governed by the laws of the Estonia, without reference to conflict of laws principles. Customer agrees that any litigation relating to this Agreement may only be brought in, and will be subject to the jurisdiction of, any competent court of the Estonia. The parties agree that the United Nations Convention on Contracts for the International Sale of Goods does not apply to this Agreement.

      +
    18. +
    19. +

      Exceptions or Modifications. For exceptions or modifications to this Agreement, please contact Aerokube at: support@aerokube.com In case the terms of this Agreement are in conflict with the terms of any agreement individually negotiated and agreed between Aerokube and Customer, the terms of the latter shall prevail.

      +
    20. +
    21. +

      Force Majeure. Except with respect to Customer’s payment obligations, neither party shall be liable to the other for any delay or failure to perform any obligation under this Agreement (except for a failure to pay fees) if the delay or failure is due to unforeseen events which occur after the signing of this Agreement and which are beyond the reasonable control of such party ("Force Majeure Event"), such as a strike, blockade, war, act of terrorism, riot, natural disaster, failure or diminishment of power or telecommunications or data networks or services, or refusal of a license by a government agency. In the event of a Force Majeure Event that prevents one part from substantially performing its obligations hereunder for a period of ten (10) days or more, either party may terminate this Agreement on five (5) days written notice.

      +
    22. +
    +
    +
  6. +
  7. +

    Grant of Rights

    +
    +
      +
    1. +

      The Product include code and libraries licensed to Licensor by third parties, including open source software.

      +
    2. +
    3. +

      The Product is provided basing on the Number of Concurrent Sessions. If Customer complies with the terms of this Agreement, Customer has the rights stipulated hereunder for each Subscription that Customer acquires. Customer’s rights acquired in relation to the Product are limited to those necessary to enable Customer and its Users to effectively operate the Product(s). All other rights remain reserved to Licensor.

      +
    4. +
    5. +

      Unless the Subscription has expired or this Agreement is terminated in accordance with respective section, and subject to the terms and conditions specified herein, Licensor grants Customer a non-exclusive and non-transferable right to use each Product covered by the Subscription as stipulated below.

      +
    6. +
    7. +

      Customer may:

      +
      +
        +
      1. +

        For each License Key included to Subscription have one Product Installation of any version covered by the Subscription on any operating system supported by the Product.

        +
      2. +
      3. +

        Make one backup copy of the Product solely for archival/security backup purposes.

        +
      4. +
      +
      +
    8. +
    9. +

      Customer may not:

      +
      +
        +
      1. +

        Allow the same Product Installation to be used concurrently by more than the Number of Concurrent Sessions specified for used License Key in Subscription Confirmation.

        +
      2. +
      3. +

        Rent, lease, reproduce, modify, adapt, create derivative works of, distribute, sell, or transfer the Product.

        +
      4. +
      5. +

        Provide access to the Product or the right to use the Product to a third party.

        +
      6. +
      7. +

        Reverse engineer, decompile, disassemble, modify, translate, make any attempt to discover the source code of the Product.

        +
      8. +
      9. +

        Remove or obscure any proprietary or other notices contained in the Product.

        +
      10. +
      +
      +
    10. +
    11. +

      Following the expiration of this Agreement, the rights stipulated in "Grant of Rights" section shall continue on a perpetual, royalty-free, non-exclusive, and non-transferable basis for the continued use of a Fallback Version of each Product covered by the Subscription. The limitations set forth in this section apply to the usage of the Fallback Version. The rights granted in this section are expressly contingent upon Customer not being in breach of this Agreement, including having paid in full the applicable Subscription fees for the preceding 12 months or longer without interruption.

      +
    12. +
    13. +

      Customer acknowledges that no ownership right is conveyed to Customer under this Agreement, irrespective of the use of terms such as "purchase" or "sale". Licensor has and retains all rights, title and interest, including all intellectual property rights, in and to the Products and any and all related or underlying technology, and any modifications or derivative works thereof, including without limitation as they may incorporate Feedback (as defined below).

      +
    14. +
    15. +

      This Agreement applies whether Customer purchases a Subscription directly from Licensor or through resellers. If Customer purchases through a reseller, the Subscription details shall be as stated in the Subscription Confirmation issued by the reseller to Customer, and the reseller is responsible for the accuracy of any such Subscription Confirmation. Resellers are not authorized to make any promises or commitments on Licensor behalf, and Customer understands and agrees that Licensor is not bound by any obligations to Customer other than as specified in this Agreement.

      +
    16. +
    +
    +
  8. +
  9. +

    Access to Products

    +
    +
      +
    1. +

      All deliveries under this Agreement will be electronic. Customer and its Users must have an Internet connection in order to receive any deliveries. For the avoidance of doubt, Customer is responsible for downloading and installing the Products. Download instructions are made available on Licensor website at http://aerokube.com.

      +
    2. +
    3. +

      Customer enables full access to Product Installation by specifying a License Key from Subscription Confirmation.

      +
    4. +
    5. +

      Subject to the terms of this Agreement, Customer is granted a right to install and use the Product for evaluation purposes without charge for unlimited amount of time. The Product contains a feature that will automatically limit allowed Number of Concurrent Sessions. Licensor reserves the right at any time to change that limit in new Product versions.

      +
    6. +
    +
    +
  10. +
  11. +

    Fees

    +
    +
      +
    1. +

      Customer shall pay its Subscription fees in accordance with Licensor Terms of Purchase or the reseller’s terms of purchase, whichever are applicable.

      +
    2. +
    3. +

      The Subscription fees shall be paid in full, and any levies, duties and/or taxes imposed by Customer’s jurisdiction (including, but not limited to, value added tax, sales tax and withholding tax), shall be borne solely by Customer.

      +
    4. +
    5. +

      Customer may not deduct any amounts from fees payable to Licensor or the reseller, unless otherwise specified in the applicable terms of purchase.

      +
    6. +
    +
    +
  12. +
  13. +

    Feedback

    +
    +
      +
    1. +

      Customer has no obligation to provide Licensor with ideas, suggestions, or proposals ("Feedback").

      +
    2. +
    3. +

      If Customer or Users submit Feedback to Licensor, then Customer grants Licensor a non-exclusive, worldwide, royalty-free license that is sub-licensable and transferable, to make, use, sell, have made, offer to sell, import, reproduce, publicly display, distribute, modify, or publicly perform the Feedback in any manner without any obligation, royalty or restriction based on intellectual property rights or otherwise.

      +
    4. +
    +
    +
  14. +
  15. +

    LIMITED WARRANTY

    +
    +

    ALL PRODUCTS ARE PROVIDED TO CUSTOMER ON AN "AS IS" AND "AS AVAILABLE" BASIS WITHOUT WARRANTIES. USE OF THE PRODUCTS IS AT YOUR OWN RISK. AEROKUBE MAKES NO WARRANTY AS TO THEIR USE OR PERFORMANCE. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, AEROKUBE, AND ITS SUPPLIERS (WHICH SHALL INCLUDE THE PROVIDERS OF THE THIRD PARTY SOFTWARE) AND RESELLERS, DISCLAIM ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, WITH REGARD TO THE PRODUCTS, AND THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES CUSTOMER SPECIFIC LEGAL RIGHTS. CUSTOMER MAY HAVE OTHER RIGHTS, WHICH VARY FROM STATE/JURISDICTION TO STATE/JURISDICTION. AEROKUBE (AND ITS AFFILIATES, AGENTS, DIRECTORS AND EMPLOYEES) DOES NOT WARRANT:

    +
    +
    +
      +
    1. +

      THAT THE PRODUCTS ARE ACCURATE, RELIABLE OR CORRECT

      +
    2. +
    3. +

      THAT THE PRODUCTS WILL MEET YOUR REQUIREMENTS

      +
    4. +
    5. +

      THAT THE PRODUCTS WILL BE AVAILABLE AT ANY PARTICULAR TIME OR LOCATION, UNINTERRUPTED OR SECURE

      +
    6. +
    7. +

      THAT ANY DEFECTS OR ERRORS WILL BE CORRECTED

      +
    8. +
    9. +

      THAT THE PRODUCTS ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS

      +
    10. +
    +
    +
    +

    ANY CONTENT OR DATA DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE PRODUCTS ARE DOWNLOADED AT YOUR OWN RISK AND YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR PROPERTY OR LOSS OF DATA THAT RESULTS FROM SUCH DOWNLOAD. NO WARRANTY OR LIABILITY AT ALL IS GIVEN TO PRODUCTS UNDER EVALUATION.

    +
    +
  16. +
  17. +

    DISCLAIMER OF DAMAGES

    +
    +
      +
    1. +

      TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL AEROKUBE (OR ITS AFFILIATES, AGENTS, DIRECTORS, OR EMPLOYEES), OR AEROKUBE LICENSORS, SUPPLIERS OR RESELLERS BE LIABLE TO CUSTOMER OR ANYONE ELSE FOR:

      +
      +
        +
      1. +

        ANY LOSS OF USE, DATA, GOODWILL, OR PROFITS, WHETHER OR NOT FORESEEABLE

        +
      2. +
      3. +

        ANY LOSS OR DAMAGES IN CONNECTION WITH TERMINATION OR SUSPENSION OF CUSTOMER’S ACCESS TO OUR PRODUCTS IN ACCORDANCE WITH THIS AGREEMENT

        +
      4. +
      5. +

        ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, EXEMPLARY OR PUNITIVE DAMAGES WHATSOEVER (EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF THESE DAMAGES), INCLUDING THOSE:

        +
        +
          +
        1. +

          RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER OR NOT FORESEEABLE

          +
        2. +
        3. +

          BASED ON ANY THEORY OF LIABILITY, INCLUDING BREACH OF CONTRACT OR WARRANTY, STRICT LIABILITY, NEGLIGENCE OR OTHER TORTIOUS ACTION

          +
        4. +
        5. +

          ARISING FROM ANY OTHER CLAIM ARISING OUT OF OR IN CONNECTION WITH CUSTOMER’S USE OF OR ACCESS TO THE PRODUCTS OR SUPPORT.

          +
        6. +
        +
        +
      6. +
      +
      +
    2. +
    3. +

      THE FOREGOING LIMITATION OF LIABILITY SHALL APPLY TO THE FULLEST EXTENT PERMITTED BY LAW IN THE APPLICABLE JURISDICTION.

      +
    4. +
    5. +

      OUR TOTAL LIABILITY IN ANY MATTER ARISING OUT OF OR IN RELATION TO THIS AGREEMENT IS LIMITED TO ONE HUNDRED (100) US DOLLARS OR THE AGGREGATE AMOUNT PAID OR PAYABLE BY THE CUSTOMER FOR PRODUCTS DURING THE THREE-MONTH PERIOD PRECEDING THE EVENT GIVING RISE TO THE LIABILITY, WHICHEVER IS GREATER. THIS LIMITATION WILL APPLY EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF LIABILITY EXCEEDING SUCH AMOUNT AND NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.

      +
    6. +
    +
    +
  18. +
  19. +

    Term and Termination

    +
    +
      +
    1. +

      The term of this Agreement will commence upon acceptance of this Agreement by Customer as set forth in the preamble above, and will continue for each Product through the end of the applicable subscription period specified in the respective Subscription Confirmation. This Agreement will automatically renew with respect to each Product for a successive subscription term, unless terminated as set forth herein.

      +
    2. +
    3. +

      Customer may terminate this Agreement at any time by cancelling its Product subscription. If such termination occurs during a then-current subscription period, this Agreement will continue to be effective until the end of that subscription period. Such termination does not relieve Customer of the obligation to pay any outstanding subscription fees owed to Licensor, and no credits or refunds will be issued to Customer for prepaid subscription fees (except as specified in the Licensor Terms of Purchase, if applicable).

      +
    4. +
    5. +

      Licensor may terminate this agreement if:

      +
      +
        +
      1. +

        Customer has materially breached this Agreement and fails to cure such breach within thirty (30) days of written notice thereof.

        +
      2. +
      3. +

        Customer fails to make the timely payment of subscription fees in accordance with "Fees" Section of this Agreement.

        +
      4. +
      5. +

        Licensor is required to do so by law (for example, where the provision of the Product to Customer is, or becomes, unlawful).

        +
      6. +
      7. +

        Licensor elects to discontinue providing the Product, in whole or in part.

        +
      8. +
      +
      +
    6. +
    7. +

      Licensor will make reasonable efforts to notify Customer via email as follows:

      +
      +
        +
      1. +

        Thirty (30) days prior to termination of the Agreement when required to terminate by law or because of discontinued Product. In such events Customer will be entitled to a refund of the unused portion of prepaid subscription fees, if applicable.

        +
      2. +
      3. +

        Three (3) days prior to termination of the Agreement in other cases. In such events Customer will not be entitled to any refund of the unused portion of prepaid subscription fees.

        +
      4. +
      +
      +
    8. +
    9. +

      Survival. Upon the expiration or termination of this Agreement by Customer and if Customer elects to use the Fallback Version of the Product this Agreement statements will also survive with respect to said Fallback Version.

      +
    10. +
    +
    +
  20. +
  21. +

    Temporary Suspension for Non-payment

    +
  22. +
  23. +

    Licensor reserves the right to suspend or limit Customer’s access to Aerokube Products if Customer fails to pay subscription fees on time.

    +
  24. +
  25. +

    If Licensor suspends or limits Customer’s access to Aerokube Products for non-payment according, Customer must pay all past due amounts in order to restore full access to Aerokube Products.

    +
  26. +
  27. +

    Customer hereby agrees that Licensor is entitled to charge Customer for the time period during which Customer has access to Aerokube Products until Customer or Licensor terminates or suspends Customer’s subscription in accordance with this Agreement.

    +
  28. +
  29. +

    Export Regulations

    +
    +

    Customer shall comply with all applicable laws and regulations with regards to economic sanctions, export controls, import regulations, and trade embargoes (all herein referred to as "Sanctions"), including those of the European Union and United States (specifically the Export Administration Regulations (EAR)). Customer declares that it is not a person targeted by Sanctions nor is it otherwise owned or controlled by or acting on behalf of any person targeted by Sanctions. Further, Customer warrants that it will not download or otherwise export or re-export the Product or any related technical data directly or indirectly to any person targeted by Sanctions or download or otherwise use the Product for any end-use prohibited or restricted by Sanctions.

    +
    +
  30. +
  31. +

    Customer Support

    +
    +
      +
    1. +

      Licensor provides Email Support as well as Instant Messaging Support. The response time will be reasonable, but no specific response time guarantees are given.

      +
    2. +
    3. +

      Customer may request additional paid support from Licensor which is subject of a supplementary individually negotiated Agreement between Customer and Licensor.

      +
    4. +
    5. +

      Any guarantees of support availability only apply to the latest version of Licensed Software available in Customer Subscription.

      +
    6. +
    +
    +
  32. +
  33. +

    Customer Data

    +
    +
      +
    1. +

      Use of Name and Logo. Customer agrees that Licensor may identify it as a customer of Aerokube and may refer to it by name, trade name and trademark, if applicable. Licensor may also briefly describe Customer’s business in Licensor marketing materials, on the Aerokube website and/or in public or legal documents. Customer hereby grants Licensor a worldwide, non-exclusive and royalty-free license to use Customer’s name and any of Customer’s trade names and trademarks solely pursuant to this marketing section.

      +
    2. +
    3. +

      Gathering of Usage Statistics. Customer acknowledges and agrees that the Product may contain a feature that reports the usage statistics, diagnostics information and usage meta-information of the Product back to the Licensor. Customer may opt out of the gathering of usage statistics by turning off this feature in the Product settings.

      +
    4. +
    +
    +
  34. +
+
+
+
+
+

Appendix A: Pricing

+
+
+
    +
  1. +

    Moon price is calculated using so-called Number of Concurrent Sessions that is to say total number of browser sessions being run in parallel. We control this by limiting total number of simultaneously running browser pods to the value you are purchasing.

    +
  2. +
  3. +

    When no license key is provided 4 (four) parallel browser sessions maximum are allowed. If such limit is sufficient for you - you are allowed use Moon without license key for unlimited period of time.

    +
  4. +
  5. +

    If free limit is insufficient - you need a paid license. Such license can include any desired number of parallel browser sessions (yes, even 42).

    +
  6. +
  7. +

    Every parallel session has a fixed cost - $5 USD (five United States dollars).

    +
    +
    An example price calculation
    +
    +
    42 sessions * $5/month = $210/month
    +
    +
    +
  8. +
  9. +

    For simplicity we calculated monthly prices for some frequent cases:

    +
  10. +
+
+ + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Table 7. Moon License Pricing
Number of Parallel SessionsPrice per Month, USD

0-4

free

5

$25

10

$50

15

$75

20

$100

25

$125

30

$150

40

$200

50

$250

75

$375

100

$500

150

$750

200

$1000

250

$1250

500

$2500

750

$2750

1000

$5000

+
+
+
+

Appendix B: Example Configuration Files

+
+
+
Example moon-sessions.yaml file contents
+
+
apiVersion: v1
+kind: ResourceQuota
+metadata:
+  name: max-moon-sessions
+spec:
+  hard:
+    pods: "6"
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+  name: moon-rbac
+subjects:
+  - kind: ServiceAccount
+    name: default
+    namespace: default
+roleRef:
+  kind: ClusterRole
+  name: cluster-admin
+  apiGroup: rbac.authorization.k8s.io
+
+
+
+
Example moon.yaml file contents
+
+
kind: Service
+apiVersion: v1
+metadata:
+  name: moon
+spec:
+  selector:
+    app: moon
+  ports:
+  - protocol: TCP
+    port: 4444
+  type: NodePort
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+  name: moon
+spec:
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: moon
+    spec:
+      containers:
+      - name: moon
+        image: aerokube/moon:1.3.2
+        resources:
+          limits:
+            cpu: "1"
+            memory: "512Mi"
+          requests:
+            cpu: "0.25"
+            memory: "64Mi"
+        ports:
+        - containerPort: 4444
+        volumeMounts:
+        - name: quota
+          mountPath: /quota
+          readOnly: true
+        - name: users
+          mountPath: /users
+          readOnly: true
+      volumes:
+      - name: quota
+        configMap:
+          name: quota
+      - name: users
+        secret:
+          secretName: users
+
+
+
+
Example moon-api.yaml file contents
+
+
kind: Service
+apiVersion: v1
+metadata:
+  name: moon-api
+spec:
+  selector:
+    app: moon-api
+  ports:
+  - protocol: TCP
+    port: 8080
+  type: NodePort
+---
+apiVersion: apps/v1beta1
+kind: Deployment
+metadata:
+  name: moon-api
+spec:
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: moon-api
+    spec:
+      containers:
+      - name: moon-api
+        image: aerokube/moon-api:1.3.2
+        resources:
+          limits:
+            cpu: "0.25"
+            memory: "128Mi"
+          requests:
+            cpu: "0.1"
+            memory: "64Mi"
+        ports:
+        - containerPort: 8080
+        volumeMounts:
+        - name: quota
+          mountPath: /quota
+      volumes:
+      - name: quota
+        configMap:
+          name: quota
+      - name: users
+        secret:
+          secretName: users
+
+
+
+
Example browsers.json file contents
+
+
{
+  "firefox": {
+    "default": "58.0",
+    "versions": {
+      "58.0": {
+        "image": "selenoid/vnc:firefox_58.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "57.0": {
+        "image": "selenoid/vnc:firefox_57.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "56.0": {
+        "image": "selenoid/vnc:firefox_56.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "55.0": {
+        "image": "selenoid/vnc:firefox_55.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "54.0": {
+        "image": "selenoid/vnc:firefox_54.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "53.0": {
+        "image": "selenoid/vnc:firefox_53.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "52.0": {
+        "image": "selenoid/vnc:firefox_52.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "51.0": {
+        "image": "selenoid/vnc:firefox_51.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "50.0": {
+        "image": "selenoid/vnc:firefox_50.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "49.0": {
+        "image": "selenoid/vnc:firefox_49.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "48.0": {
+        "image": "selenoid/vnc:firefox_48.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "47.0": {
+        "image": "selenoid/vnc:firefox_47.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "46.0": {
+        "image": "selenoid/vnc:firefox_46.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "45.0": {
+        "image": "selenoid/vnc:firefox_45.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "44.0": {
+        "image": "selenoid/vnc:firefox_44.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "43.0": {
+        "image": "selenoid/vnc:firefox_43.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "42.0": {
+        "image": "selenoid/vnc:firefox_42.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "41.0": {
+        "image": "selenoid/vnc:firefox_41.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "40.0": {
+        "image": "selenoid/vnc:firefox_40.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "39.0": {
+        "image": "selenoid/vnc:firefox_39.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "38.0": {
+        "image": "selenoid/vnc:firefox_38.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "37.0": {
+        "image": "selenoid/vnc:firefox_37.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "36.0": {
+        "image": "selenoid/vnc:firefox_36.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "35.0": {
+        "image": "selenoid/vnc:firefox_35.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "34.0": {
+        "image": "selenoid/vnc:firefox_34.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "33.0": {
+        "image": "selenoid/vnc:firefox_33.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "32.0": {
+        "image": "selenoid/vnc:firefox_32.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "31.0": {
+        "image": "selenoid/vnc:firefox_31.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "30.0": {
+        "image": "selenoid/vnc:firefox_30.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "29.0": {
+        "image": "selenoid/vnc:firefox_29.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "28.0": {
+        "image": "selenoid/vnc:firefox_28.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "27.0": {
+        "image": "selenoid/vnc:firefox_27.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "26.0": {
+        "image": "selenoid/vnc:firefox_26.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "25.0": {
+        "image": "selenoid/vnc:firefox_25.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "24.0": {
+        "image": "selenoid/vnc:firefox_24.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "23.0": {
+        "image": "selenoid/vnc:firefox_23.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "22.0": {
+        "image": "selenoid/vnc:firefox_22.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "21.0": {
+        "image": "selenoid/vnc:firefox_21.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "20.0": {
+        "image": "selenoid/vnc:firefox_20.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "19.0": {
+        "image": "selenoid/vnc:firefox_19.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "18.0": {
+        "image": "selenoid/vnc:firefox_18.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "17.0": {
+        "image": "selenoid/vnc:firefox_17.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "16.0": {
+        "image": "selenoid/vnc:firefox_16.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "15.0": {
+        "image": "selenoid/vnc:firefox_15.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "14.0": {
+        "image": "selenoid/vnc:firefox_14.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "13.0": {
+        "image": "selenoid/vnc:firefox_13.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "12.0": {
+        "image": "selenoid/vnc:firefox_12.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "11.0": {
+        "image": "selenoid/vnc:firefox_11.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "10.0": {
+        "image": "selenoid/vnc:firefox_10.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "9.0": {
+        "image": "selenoid/vnc:firefox_9.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "8.0": {
+        "image": "selenoid/vnc:firefox_8.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "7.0": {
+        "image": "selenoid/vnc:firefox_7.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "6.0": {
+        "image": "selenoid/vnc:firefox_6.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "5.0": {
+        "image": "selenoid/vnc:firefox_5.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "4.0": {
+        "image": "selenoid/vnc:firefox_4.0",
+        "port": "4444",
+        "path": "/wd/hub"
+      },
+      "3.6": {
+        "image": "selenoid/vnc:firefox_3.6",
+        "port": "4444",
+        "path": "/wd/hub"
+      }
+    }
+  },
+  "chrome": {
+    "default": "65.0",
+    "versions": {
+      "65.0": {
+        "image": "selenoid/vnc:chrome_65.0",
+        "port": "4444"
+      },
+      "64.0": {
+        "image": "selenoid/vnc:chrome_64.0",
+        "port": "4444"
+      },
+      "63.0": {
+        "image": "selenoid/vnc:chrome_63.0",
+        "port": "4444"
+      },
+      "62.0": {
+        "image": "selenoid/vnc:chrome_62.0",
+        "port": "4444"
+      },
+      "61.0": {
+        "image": "selenoid/vnc:chrome_61.0",
+        "port": "4444"
+      },
+      "60.0": {
+        "image": "selenoid/vnc:chrome_60.0",
+        "port": "4444"
+      },
+      "59.0": {
+        "image": "selenoid/vnc:chrome_59.0",
+        "port": "4444"
+      },
+      "58.0": {
+        "image": "selenoid/vnc:chrome_58.0",
+        "port": "4444"
+      },
+      "57.0": {
+        "image": "selenoid/vnc:chrome_57.0",
+        "port": "4444"
+      },
+      "56.0": {
+        "image": "selenoid/vnc:chrome_56.0",
+        "port": "4444"
+      },
+      "55.0": {
+        "image": "selenoid/vnc:chrome_55.0",
+        "port": "4444"
+      },
+      "54.0": {
+        "image": "selenoid/vnc:chrome_54.0",
+        "port": "4444"
+      },
+      "53.0": {
+        "image": "selenoid/vnc:chrome_53.0",
+        "port": "4444"
+      },
+      "52.0": {
+        "image": "selenoid/vnc:chrome_52.0",
+        "port": "4444"
+      },
+      "51.0": {
+        "image": "selenoid/vnc:chrome_51.0",
+        "port": "4444"
+      },
+      "50.0": {
+        "image": "selenoid/vnc:chrome_50.0",
+        "port": "4444"
+      },
+      "49.0": {
+        "image": "selenoid/vnc:chrome_49.0",
+        "port": "4444"
+      },
+      "48.0": {
+        "image": "selenoid/vnc:chrome_48.0",
+        "port": "4444"
+      }
+    }
+  },
+  "opera": {
+    "default": "50.0",
+    "versions": {
+      "50.0": {
+        "image": "selenoid/vnc:opera_50.0",
+        "port": "4444"
+      },
+      "49.0": {
+        "image": "selenoid/vnc:opera_49.0",
+        "port": "4444"
+      },
+      "48.0": {
+        "image": "selenoid/vnc:opera_48.0",
+        "port": "4444"
+      },
+      "47.0": {
+        "image": "selenoid/vnc:opera_47.0",
+        "port": "4444"
+      },
+      "46.0": {
+        "image": "selenoid/vnc:opera_46.0",
+        "port": "4444"
+      },
+      "45.0": {
+        "image": "selenoid/vnc:opera_45.0",
+        "port": "4444"
+      },
+      "44.0": {
+        "image": "selenoid/vnc:opera_44.0",
+        "port": "4444"
+      },
+      "43.0": {
+        "image": "selenoid/vnc:opera_43.0",
+        "port": "4444"
+      },
+      "42.0": {
+        "image": "selenoid/vnc:opera_42.0",
+        "port": "4444"
+      },
+      "41.0": {
+        "image": "selenoid/vnc:opera_41.0",
+        "port": "4444"
+      },
+      "40.0": {
+        "image": "selenoid/vnc:opera_40.0",
+        "port": "4444"
+      },
+      "39.0": {
+        "image": "selenoid/vnc:opera_39.0",
+        "port": "4444"
+      },
+      "38.0": {
+        "image": "selenoid/vnc:opera_38.0",
+        "port": "4444"
+      },
+      "37.0": {
+        "image": "selenoid/vnc:opera_37.0",
+        "port": "4444"
+      },
+      "36.0": {
+        "image": "selenoid/vnc:opera_36.0",
+        "port": "4444"
+      },
+      "35.0": {
+        "image": "selenoid/vnc:opera_35.0",
+        "port": "4444"
+      },
+      "34.0": {
+        "image": "selenoid/vnc:opera_34.0",
+        "port": "4444"
+      },
+      "33.0": {
+        "image": "selenoid/vnc:opera_33.0",
+        "port": "4444"
+      },
+      "12.1": {
+        "image": "selenoid/vnc:opera_12.1",
+        "port": "4444",
+        "path": "/wd/hub"
+      }
+    }
+  }
+}
+
+
+
+
Example moon-config/service.json file contents
+
+
{
+  "images": {
+    "videoRecorder": "aerokube/moon-video-recorder:devel",
+    "defender": "aerokube/defender:devel",
+    "logger": "aerokube/logger:devel"
+  }
+}
+
+
+
+
Example moon-openshift.yaml file contents
+
+
kind: Template
+apiVersion: v1
+metadata:
+  name: moon
+objects:
+
+  - kind: ResourceQuota
+    apiVersion: v1
+    metadata:
+      name: max-moon-sessions
+    spec:
+      hard:
+        pods: ${MOON_PODS}
+
+  - kind: Service
+    apiVersion: v1
+    metadata:
+      name: moon
+    spec:
+      selector:
+        app: moon
+      ports:
+      - name: moon
+        protocol: TCP
+        port: 4444
+      type: NodePort
+
+  - kind: Service
+    apiVersion: v1
+    metadata:
+      name: moon-api
+    spec:
+      selector:
+        app: moon-api
+      ports:
+      - name: moon-api
+        protocol: TCP
+        port: 8080
+      type: NodePort
+
+  - kind: Service
+    apiVersion: v1
+    metadata:
+      name: moon-ui
+    spec:
+      selector:
+        app: moon-ui
+      ports:
+      - name: moon-ui
+        protocol: TCP
+        port: 8080
+      type: NodePort
+
+  - kind: DeploymentConfig
+    apiVersion: v1
+    metadata:
+      name: moon
+    spec:
+      replicas: 1
+      template:
+        metadata:
+          labels:
+            app: moon
+        spec:
+          containers:
+          - name: moon
+            image: ${MOON_IMAGE}
+            args:
+              - '-namespace'
+              - '${NAMESPACE}'
+            resources:
+              limits:
+                cpu: "1"
+                memory: "512Mi"
+              requests:
+                cpu: "0.25"
+                memory: "64Mi"
+            ports:
+            - containerPort: 4444
+            volumeMounts:
+            - name: quota
+              mountPath: /quota
+              readOnly: true
+            - name: users
+              mountPath: /users
+              readOnly: true
+          volumes:
+          - name: quota
+            configMap:
+              name: quota
+          - name: users
+            secret:
+              secretName: users
+
+  - kind: DeploymentConfig
+    apiVersion: v1
+    metadata:
+      name: moon-api
+    spec:
+      replicas: 1
+      template:
+        metadata:
+          labels:
+            app: moon-api
+        spec:
+          containers:
+          - name: moon-api
+            image: ${MOON_API_IMAGE}
+            args:
+              - '-namespace'
+              - '${NAMESPACE}'
+            resources:
+              limits:
+                cpu: "0.25"
+                memory: "128Mi"
+              requests:
+                cpu: "0.1"
+                memory: "64Mi"
+            ports:
+            - containerPort: 8080
+            volumeMounts:
+            - name: quota
+              mountPath: /quota
+          volumes:
+          - name: quota
+            configMap:
+              name: quota
+          - name: users
+            secret:
+              secretName: users
+
+  - kind: DeploymentConfig
+    apiVersion: v1
+    metadata:
+      name: moon-ui
+    spec:
+      replicas: 1
+      template:
+        metadata:
+          labels:
+            app: moon-ui
+        spec:
+          containers:
+            - name: moon-ui
+              args:
+                - '--selenoid-uri'
+                - 'http://moon-api:8080'
+              image: ${MOON_UI_IMAGE}
+              ports:
+                - containerPort: 8080
+                  protocol: TCP
+              resources:
+                limits:
+                  cpu: 100m
+                  memory: 64M
+
+parameters:
+- name: NAMESPACE
+  displayName: Namespace
+  description: Namespace where the Moon is running
+  value: default
+  required: true
+
+- name: MOON_IMAGE
+  displayName: Moon docker image
+  description: Name of the image to be used.
+  value: aerokube/moon:latest-release
+  required: true
+
+- name: MOON_API_IMAGE
+  displayName: Moon-API docker image
+  description: Name of the image to be used.
+  value: aerokube/moon-api:latest-release
+  required: true
+
+- name: MOON_UI_IMAGE
+  displayName: Moon-UI docker image
+  description: Name of the image to be used.
+  value: aerokube/selenoid-ui:latest-release
+  required: true
+
+- name: MOON_PODS
+  displayName: Max moon pods in project
+  description: Specify max moon pods for project (4 free slots + Moon + Moon API + Moon UI = 7).
+  value: '7'
+  required: true
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/latest-release/files/moon-api.yaml b/latest-release/files/moon-api.yaml index cfae833..8fa396c 100644 --- a/latest-release/files/moon-api.yaml +++ b/latest-release/files/moon-api.yaml @@ -23,7 +23,7 @@ spec: spec: containers: - name: moon-api - image: aerokube/moon-api:1.3.1 + image: aerokube/moon-api:1.3.2 resources: limits: cpu: "0.25" diff --git a/latest-release/files/moon.yaml b/latest-release/files/moon.yaml index 24e86ca..f21d953 100644 --- a/latest-release/files/moon.yaml +++ b/latest-release/files/moon.yaml @@ -23,7 +23,7 @@ spec: spec: containers: - name: moon - image: aerokube/moon:1.3.1 + image: aerokube/moon:1.3.2 resources: limits: cpu: "1" diff --git a/latest-release/index.html b/latest-release/index.html index 3b57de6..3e01895 100644 --- a/latest-release/index.html +++ b/latest-release/index.html @@ -524,7 +524,7 @@

Moon

Aerokube OÜ
version latest-release, -2018-12-29 +2019-01-04
Table of Contents
@@ -554,8 +554,43 @@

Moon

  • 2.3. Configuration File
  • 2.4. Credentials Secret
  • +
  • 2.5. Installing License
  • +
  • 2.6. Advanced Configuration + +
  • +
  • 2.7. Log Files
  • +
  • 2.8. CLI Flags
  • + + +
  • 3. Advanced Features +
  • +
  • 4. License Agreement
  • +
  • Appendix A: Pricing
  • +
  • Appendix B: Example Configuration Files
  • @@ -696,7 +731,7 @@

    [Example Configuration Files] section.

    +

    Example YAML and JSON files can be found in Example Configuration Files section.

  • Add view policy to default account so Moon could read project pod quota:

    @@ -1236,1454 +1271,2379 @@

    2

    s3.secretKey

    -

    S3 secret key value

    -

    :leveloffset!: -:leveloffset: +1

    -

    == Installing License -NOTE: According to license agreement you can use up to 4 parallel sessions without a license. If you wish to have more parallel sessions - order a license and follow this section steps to install the license.

    -

    . To install a license you should have a license key file. A typical license file looks like this:

    -

    $ cat license.key - Ti90a3ljSWpvV3hicU5ZY3U3ZVNMUzdzalVjU29nSVU2a3lmWDdENmhOSEs4SFJVVE5LNEpKL2oxRGhWTnRhZVBEQmx5cm1SM0dFWlVpbGIwOWhBSUpvWmlQMnNtYmtoZVRDbnJ3UTlIV3grMUMzaXFJalU3L0NIZDJuSzN3QUpIS0lyV2VoVjlRVUh5NzNCMFg0NEV5KzFSVXg1elhvaC9RUkNjTlBIOHR4WWtrRFBmTFhxYTFESlI0aXNObGtobWpXY2VJNVdna1lsWHFFOUp0OUxValZPN05hb2pCcHJzY0pvZjBrZys2YkhWUDR3cUJvYVFoSFJTYzMzZzNRSTkrWVd4dlZCeExmdTVxM2k2ZnluMDRHSEhGc21Fd2owVHdVa1Z3MmI5Z2FyVXlaVFF4RDdCRjVSVjBmSUVrU1pEQ0ZQdmIvMHZoKythY1V4OVRrR2FBREZzbWR3dExxRlU4NHF3MzBVdE5nTGhnNWYxRXRCQ215R1BHR0wyK2NpR0RDZDBTSXg4K1RsRGNWVzUyVVY4MUt6bkdOanJhTklOeXVtYjVPVXF6aVVpdmJZeVJNVVBSMWF3NUJRVGJDaHVycWVVdGtMMWFRZDgwOCtoWGRxODFOakxRNEJlVENNQTdPL2FneHBTUE1nL0J2QmVQKy84ZGhJeXd5Y0lxQVJhVWxocUdmUko2K05tbkFYV0hzZ2RjTng1dUVHU0w5VWF5TU1rR3RkZEZKQ1FiWmF0RnJMaDFHbHhKTndBRHFWcXIvQ0oxSzBQL2p6K2NFSWpsSG82TktvM3pudVFlanhYT2tGU1p1bWZrS1krZmF3VkVRZWlvcFlmZFk0TU9tc3U5TThsbng3T2VXQXZmOTFUQ2w1NUhBK1ZsQTMzN3VFOG1WV3ZlS0E1Tlk9O2V5SnNhV05sYm5ObFpTSTZJa0ZqYldVZ1RFeERJaXdpY0hKdlpIVmpkQ0k2SWsxdmIyNGlMQ0p0WVhoVFpYTnphVzl1Y3lJNk1qQXNJblJ2SWpveE5UTTRNelV5TURBd2ZRPT0=

    -

    + -Moon container is expecting to find license key file in the path specified by -license-file parameter. You need to mount license key file as a volume to every Moon container

    -

    . Having a license key file - create a Kubernetes secret:

    -

    $ kubectl create secret generic license-key --from-file /path/to/license.key -n moon

    -

    + -If you prefer YAML - this will look like: -+ -.Creating a secret for license key -[source,yaml] ----- -apiVersion: v1 -kind: Secret -metadata: - name: license-key - namespace: moon -stringData: - license.key: Ti90a3ljSWpvV3hicU5ZY3U3ZVNMUzdzalVjU29nSVU2a3lmWDdENmhOSEs4SFJVVE5LNEpKL2oxRGhWTnRhZVBEQmx5cm1SM0dFWlVpbGIwOWhBSUpvWmlQMnNtYmtoZVRDbnJ3UTlIV3grMUMzaXFJalU3L0NIZDJuSzN3QUpIS0lyV2VoVjlRVUh5NzNCMFg0NEV5KzFSVXg1elhvaC9RUkNjTlBIOHR4WWtrRFBmTFhxYTFESlI0aXNObGtobWpXY2VJNVdna1lsWHFFOUp0OUxValZPN05hb2pCcHJzY0pvZjBrZys2YkhWUDR3cUJvYVFoSFJTYzMzZzNRSTkrWVd4dlZCeExmdTVxM2k2ZnluMDRHSEhGc21Fd2owVHdVa1Z3MmI5Z2FyVXlaVFF4RDdCRjVSVjBmSUVrU1pEQ0ZQdmIvMHZoKythY1V4OVRrR2FBREZzbWR3dExxRlU4NHF3MzBVdE5nTGhnNWYxRXRCQ215R1BHR0wyK2NpR0RDZDBTSXg4K1RsRGNWVzUyVVY4MUt6bkdOanJhTklOeXVtYjVPVXF6aVVpdmJZeVJNVVBSMWF3NUJRVGJDaHVycWVVdGtMMWFRZDgwOCtoWGRxODFOakxRNEJlVENNQTdPL2FneHBTUE1nL0J2QmVQKy84ZGhJeXd5Y0lxQVJhVWxocUdmUko2K05tbkFYV0hzZ2RjTng1dUVHU0w5VWF5TU1rR3RkZEZKQ1FiWmF0RnJMaDFHbHhKTndBRHFWcXIvQ0oxSzBQL2p6K2NFSWpsSG82TktvM3pudVFlanhYT2tGU1p1bWZrS1krZmF3VkVRZWlvcFlmZFk0TU9tc3U5TThsbng3T2VXQXZmOTFUQ2w1NUhBK1ZsQTMzN3VFOG1WV3ZlS0E1Tlk9O2V5SnNhV05sYm5ObFpTSTZJa0ZqYldVZ1RFeERJaXdpY0hKdlpIVmpkQ0k2SWsxdmIyNGlMQ0p0WVhoVFpYTnphVzl1Y3lJNk1qQXNJblJ2SWpveE5UTTRNelV5TURBd2ZRPT0= -----

    -

    . When starting Moon - mount this secret as a volume and point -license-file to mounted file: -+ -.Starting Moon with license key -[source,yaml] ----- -apiVersion: apps/v1beta1 -kind: Deployment -metadata: - name: moon - namespace: moon -spec: - replicas: 3 - template: - metadata: - labels: - app: moon - spec: - containers: - - name: moon - image: aerokube/moon:latest-release - args: ["-license-file", "/license/license.key"] # Pointing to license key file - resources: - # Resources here - ports: - # Ports here - volumeMounts: - # Other mounts here - - name: license-key # Mounting volume with license key - mountPath: /license - readOnly: true - volumes: - # Other volumes here - - name: license-key # Creating volume from secret - secret: - secretName: license-key -----

    -

    :leveloffset: 1 -:leveloffset: +1

    -

    == Advanced Configuration

    -

    === Uploading Files to S3

    -

    You can configure Moon to send sessions logs and recorded video files to S3-compatible storage. Such type of storage is supported by AWS, Google Cloud, Microsoft Azure, Digital Ocean and many other cloud providers. To deploy a private S3-compatible storage you can use Minio. To enable S3 support in Moon:

    -

    . Create an S3 bucket. In this example bucket name is moon-test. You will get an access key and a secret key for the bucket. Also you need to know supported S3 protocol version (usually specified in documentation). -. Create a service.json file with the following contents:

    -

    $ cat service.json - { - "s3": { - "endpoint": "https://storage.googleapis.com", - "bucketName": "moon-test", - "version": "S3v2" - } - }

    -

    . Save service.json to a Kubernetes config map, mount it as a file to Moon container and then specify path to the file using -config-file flag as shown in Configuration File section. -. Create a credentials.json file to store S3 keys:

    -

    $ cat service.json - { - "s3": { - "accessKey": "access-key-value", - "secretKey": "secret-key-value" - } - }

    -

    . Save credentials.json to a Kubernetes secret, mount it as a file to Moon container and then specify path to the file using -credentials-file flag as shown in [Credentials File] section. -. When you update a config map with service.json or a secret with credentials.json - settings are applied immediately without Moon restart.

    -

    === Using Custom Moon Images

    -

    By default Moon downloads some service images (aerokube/defender, aerokube/logger and so on) from public Docker registry. If in your environment due to security restrictions Docker images can only be downloaded from private registry you need to provide image names to Moon. To do this:

    -

    . Copy the following public images to your registry:

    -

    aerokube/moon - aerokube/moon-api - aerokube/moon-video-recorder - aerokube/defender - aerokube/logger

    -

    . Create a service.json file with the following contents:

    -

    $ cat service.json - { - "images": { - "videoRecorder": { - "image": "my-registry.example.com/moon/video-recorder:latest-release" - }, - "defender": { - "image": "my-registry.example.com/moon/defender:latest-release" - }, - "logger": { - "image": "my-registry.example.com/moon/logger:latest-release" - } - } - } -+ -If you already have S3 configuration in service.json file - just append new images key to it. -+ -You can optionally adjust CPU and memory limits for each image as follows: -+ -.Adjusting memory and CPU limits for system images -[source,javascript] ----- -{ - "images": { - "logger": { - "image": "my-registry.example.com/moon/video-recorder:latest-release", - "cpu": "0.3", - "mem": "1024Mi" - } - } -} -----

    -

    . Save service.json to a Kubernetes config map, mount it as a file to Moon container and then specify path to the file using -config-file flag as shown in Configuration File section. -. When you update a config map with service.json - settings are applied immediately without Moon restart.

    -

    === Adjusting Timeouts

    -

    Sometimes things go wrong: user can unexpectedly disconnect or browser session starts longer than needed. This can lead to overall cluster degradation because of broken browser pods occupying all available hardware. To prevent such cases Moon automatically detects and closes suspicious browser sessions. Several flags allow to adjust timeout settings:

    -

    .Available Timeout Flags

    +

    S3 secret key value

    -
    -

    | Flag | Default Value | Meaning | Notes

    -
    -
    -

    | -timeout | 1 minute | Maximum browser session idle time - measured as maximum time between separate HTTP requests corresponding to a running session. | When this timeout expires - session is automatically closed. You may need to increase this timeout when tested application pages load too slowly. -| -session-attempt-timeout | 10 minutes | Maximum time to start browser pod. | This time includes Kubernetes scheduling time and browser image download duration.

    - --- - +
    +

    2.5. Installing License

    +
    +
    - + + -

    === Adjusting Resources Consumption

    -

    NOTE: Flags and fields described in this section apply to browser container consumption only. Other system containers started in browser pod have reasonable fixed values assigned.

    -

    Moon has reasonable defaults for resources consumed by every browser pod. Sometimes you may need to override these settings. To override resource settings globally for every browser image use one of the following flags:

    -

    .Resources Consumption Flags

    + + +According to license agreement you can use up to 4 parallel sessions without a license. If you wish to have more parallel sessions - order a license and follow this section steps to install the license. +
    + +
    +
      +
    1. +

      To install a license you should have a license key file. A typical license file looks like this:

      +
      +
      +
      $ cat license.key
      +Ti90a3ljSWpvV3hicU5ZY3U3ZVNMUzdzalVjU29nSVU2a3lmWDdENmhOSEs4SFJVVE5LNEpKL2oxRGhWTnRhZVBEQmx5cm1SM0dFWlVpbGIwOWhBSUpvWmlQMnNtYmtoZVRDbnJ3UTlIV3grMUMzaXFJalU3L0NIZDJuSzN3QUpIS0lyV2VoVjlRVUh5NzNCMFg0NEV5KzFSVXg1elhvaC9RUkNjTlBIOHR4WWtrRFBmTFhxYTFESlI0aXNObGtobWpXY2VJNVdna1lsWHFFOUp0OUxValZPN05hb2pCcHJzY0pvZjBrZys2YkhWUDR3cUJvYVFoSFJTYzMzZzNRSTkrWVd4dlZCeExmdTVxM2k2ZnluMDRHSEhGc21Fd2owVHdVa1Z3MmI5Z2FyVXlaVFF4RDdCRjVSVjBmSUVrU1pEQ0ZQdmIvMHZoKythY1V4OVRrR2FBREZzbWR3dExxRlU4NHF3MzBVdE5nTGhnNWYxRXRCQ215R1BHR0wyK2NpR0RDZDBTSXg4K1RsRGNWVzUyVVY4MUt6bkdOanJhTklOeXVtYjVPVXF6aVVpdmJZeVJNVVBSMWF3NUJRVGJDaHVycWVVdGtMMWFRZDgwOCtoWGRxODFOakxRNEJlVENNQTdPL2FneHBTUE1nL0J2QmVQKy84ZGhJeXd5Y0lxQVJhVWxocUdmUko2K05tbkFYV0hzZ2RjTng1dUVHU0w5VWF5TU1rR3RkZEZKQ1FiWmF0RnJMaDFHbHhKTndBRHFWcXIvQ0oxSzBQL2p6K2NFSWpsSG82TktvM3pudVFlanhYT2tGU1p1bWZrS1krZmF3VkVRZWlvcFlmZFk0TU9tc3U5TThsbng3T2VXQXZmOTFUQ2w1NUhBK1ZsQTMzN3VFOG1WV3ZlS0E1Tlk9O2V5SnNhV05sYm5ObFpTSTZJa0ZqYldVZ1RFeERJaXdpY0hKdlpIVmpkQ0k2SWsxdmIyNGlMQ0p0WVhoVFpYTnphVzl1Y3lJNk1qQXNJblJ2SWpveE5UTTRNelV5TURBd2ZRPT0=
      +
      +
      -

      | Flag | Default Value | Meaning

      +

      Moon container is expecting to find license key file in the path specified by -license-file parameter. You need to mount license key file as a volume to every Moon container

      +
      +
    2. +
    3. +

      Having a license key file - create a Kubernetes secret:

      +
      +
      +
      $ kubectl create secret generic license-key --from-file /path/to/license.key -n moon
      +
      -

      | -cpu-limit | 1 | Hard CPU limit for browser container (no more than this limit is given) -| -cpu-request | 1 | Soft (guaranteed) CPU limit for browser container -| -memory-limit | 1Gi | Hard memory limit for browser container -| -memory-request | 512Mi | Soft memory limit for browser container

      +

      If you prefer YAML - this will look like:

      - --- - - - - - -

      You can also override the same values for every browser image in browsers list file:

      -

      .Overriding Resources in Browsers List File -[source,javascript] ----- +

      +
      Creating a secret for license key
      +
      +
      apiVersion: v1
      +kind: Secret
      +metadata:
      +  name: license-key
      +  namespace: moon
      +stringData:
      +  license.key: Ti90a3ljSWpvV3hicU5ZY3U3ZVNMUzdzalVjU29nSVU2a3lmWDdENmhOSEs4SFJVVE5LNEpKL2oxRGhWTnRhZVBEQmx5cm1SM0dFWlVpbGIwOWhBSUpvWmlQMnNtYmtoZVRDbnJ3UTlIV3grMUMzaXFJalU3L0NIZDJuSzN3QUpIS0lyV2VoVjlRVUh5NzNCMFg0NEV5KzFSVXg1elhvaC9RUkNjTlBIOHR4WWtrRFBmTFhxYTFESlI0aXNObGtobWpXY2VJNVdna1lsWHFFOUp0OUxValZPN05hb2pCcHJzY0pvZjBrZys2YkhWUDR3cUJvYVFoSFJTYzMzZzNRSTkrWVd4dlZCeExmdTVxM2k2ZnluMDRHSEhGc21Fd2owVHdVa1Z3MmI5Z2FyVXlaVFF4RDdCRjVSVjBmSUVrU1pEQ0ZQdmIvMHZoKythY1V4OVRrR2FBREZzbWR3dExxRlU4NHF3MzBVdE5nTGhnNWYxRXRCQ215R1BHR0wyK2NpR0RDZDBTSXg4K1RsRGNWVzUyVVY4MUt6bkdOanJhTklOeXVtYjVPVXF6aVVpdmJZeVJNVVBSMWF3NUJRVGJDaHVycWVVdGtMMWFRZDgwOCtoWGRxODFOakxRNEJlVENNQTdPL2FneHBTUE1nL0J2QmVQKy84ZGhJeXd5Y0lxQVJhVWxocUdmUko2K05tbkFYV0hzZ2RjTng1dUVHU0w5VWF5TU1rR3RkZEZKQ1FiWmF0RnJMaDFHbHhKTndBRHFWcXIvQ0oxSzBQL2p6K2NFSWpsSG82TktvM3pudVFlanhYT2tGU1p1bWZrS1krZmF3VkVRZWlvcFlmZFk0TU9tc3U5TThsbng3T2VXQXZmOTFUQ2w1NUhBK1ZsQTMzN3VFOG1WV3ZlS0E1Tlk9O2V5SnNhV05sYm5ObFpTSTZJa0ZqYldVZ1RFeERJaXdpY0hKdlpIVmpkQ0k2SWsxdmIyNGlMQ0p0WVhoVFpYTnphVzl1Y3lJNk1qQXNJblJ2SWpveE5UTTRNelV5TURBd2ZRPT0=
      +
      +
      + +
    4. +

      When starting Moon - mount this secret as a volume and point -license-file to mounted file:

      +
      +
      Starting Moon with license key
      +
      +
      apiVersion: apps/v1beta1
      +kind: Deployment
      +metadata:
      +  name: moon
      +  namespace: moon
      +spec:
      +  replicas: 3
      +  template:
      +    metadata:
      +      labels:
      +        app: moon
      +    spec:
      +      containers:
      +      - name: moon
      +        image: aerokube/moon:latest-release
      +        args: ["-license-file", "/license/license.key"] # Pointing to license key file
      +        resources:
      +            # Resources here
      +        ports:
      +            # Ports here
      +        volumeMounts:
      +        # Other mounts here
      +        - name: license-key # Mounting volume with license key
      +          mountPath: /license
      +          readOnly: true
      +    volumes:
      +    # Other volumes here
      +    - name: license-key # Creating volume from secret
      +      secret:
      +        secretName: license-key
      +
      +
      +
    5. + + + +
      +

      2.6. Advanced Configuration

      +
      +

      2.6.1. Uploading Files to S3

      +
      +

      You can configure Moon to send sessions logs and recorded video files to S3-compatible storage. Such type of storage is supported by AWS, Google Cloud, Microsoft Azure, Digital Ocean and many other cloud providers. To deploy a private S3-compatible storage you can use Minio. To enable S3 support in Moon:

      +
      +
      +
        +
      1. +

        Create an S3 bucket. In this example bucket name is moon-test. You will get an access key and a secret key for the bucket. Also you need to know supported S3 protocol version (usually specified in documentation).

        +
      2. +
      3. +

        Create a service.json file with the following contents:

        +
        +
        +
        $ cat service.json
         {
        -  "firefox": {
        -    "default": "62.0",
        -    "versions": {
        -      "62.0":
        -        "image": "selenoid/firefox:62.0",
        -        "port": "4444",
        -        "path": "/wd/hub",
        -        "resources": {                              <1>
        -          "limits": {                               <2>
        -            "cpu": "2",                             <3>
        -            "memory": "2Gi"                         <4>
        -          },
        -          "requests": {                             <5>
        -            "cpu": "200m",                          <6>
        -            "memory": "1Gi"                         <7>
        -          }
        -        }
        -      }
        -    }
        +  "s3": {
        +    "endpoint": "https://storage.googleapis.com",
        +    "bucketName": "moon-test",
        +    "version": "S3v2"
           }
        -}
        -----
        -<1> Resources definition section
        -<2> Limits definition section
        -<3> CPU limit field
        -<4> Memory limit field
        -<5> Requests definition section
        -<6> CPU request field
        -<7> Memory request field

        -

        === Running Browser Pods in Privileged Mode

        -

        In some cases like running Android emulators browser container should be run in privileged mode. This setting can be applied separately to each browser version in browsers list file as follows:

        -

        .Starting Container in Privileged Mode -[source,javascript] ----- +}

        +
        +
        +
      4. +
      5. +

        Save service.json to a Kubernetes config map, mount it as a file to Moon container and then specify path to the file using -config-file flag as shown in Configuration File section.

        +
      6. +
      7. +

        Create a credentials.json file to store S3 keys:

        +
        +
        +
        $ cat service.json
         {
        -  "firefox": {
        -    "default": "62.0",
        -    "versions": {
        -      "62.0":
        -        "image": "selenoid/firefox:62.0",
        -        "port": "4444",
        -        "path": "/wd/hub",
        -        "privileged": true                  <1>
        -      }
        -    }
        +  "s3": {
        +    "accessKey": "access-key-value",
        +    "secretKey": "secret-key-value"
           }
        -}
        -----
        -<1> Launch container in privileged mode

        -

        === Using Node Selectors

        -

        Sometimes you may need to run browser pods on particular Kubernetes nodes (i.e. hardware hosts) only. Kubernetes allows to do this by specifying so called node selectors. To provide such selector to Moon browser pods update browsers list as shown below:

        -

        .Adding Node Selectors -[source,javascript] ----- +}

        +
        +
        +
      8. +
      9. +

        Save credentials.json to a Kubernetes secret, mount it as a file to Moon container and then specify path to the file using -credentials-file flag as shown in [Credentials File] section.

        +
      10. +
      11. +

        When you update a config map with service.json or a secret with credentials.json - settings are applied immediately without Moon restart.

        +
      12. +
      +
      +
      +
      +

      2.6.2. Using Custom Moon Images

      +
      +

      By default Moon downloads some service images (aerokube/defender, aerokube/logger and so on) from public Docker registry. If in your environment due to security restrictions Docker images can only be downloaded from private registry you need to provide image names to Moon. To do this:

      +
      +
      +
        +
      1. +

        Copy the following public images to your registry:

        +
        +
        +
        aerokube/moon
        +aerokube/moon-api
        +aerokube/moon-video-recorder
        +aerokube/defender
        +aerokube/logger
        +
        +
        +
      2. +
      3. +

        Create a service.json file with the following contents:

        +
        +
        +
        $ cat service.json
         {
        -  "firefox": {
        -    "default": "62.0",
        -    "versions": {
        -      "62.0":
        -        "image": "selenoid/firefox:62.0",
        -        "port": "4444",
        -        "path": "/wd/hub",
        -        "nodeSelector": {                    <1>
        -          "node-type": "hardware"
        -        },
        -      }
        +  "images": {
        +    "videoRecorder": {
        +        "image": "my-registry.example.com/moon/video-recorder:latest-release"
        +    },
        +    "defender": {
        +        "image": "my-registry.example.com/moon/defender:latest-release"
        +    },
        +    "logger": {
        +        "image": "my-registry.example.com/moon/logger:latest-release"
             }
           }
        -}
        -----
        -<1> Node selector for this browser version

        -

        :leveloffset: 1 -:leveloffset: +1

        -

        == Log Files -Every log line contains:

        -

        .Log entry contents

      +} +
    + +
    +

    If you already have S3 configuration in service.json file - just append new images key to it.

    +
    -

    | Field | Example | Notes

    +

    You can optionally adjust CPU and memory limits for each image as follows:

    +
    +
    +
    Adjusting memory and CPU limits for system images
    +
    +
    {
    +  "images": {
    +    "logger": {
    +      "image": "my-registry.example.com/moon/video-recorder:latest-release",
    +      "cpu": "0.3",
    +      "mem": "1024Mi"
    +    }
    +  }
    +}
    +
    +
    +

  • +
  • +

    Save service.json to a Kubernetes config map, mount it as a file to Moon container and then specify path to the file using -config-file flag as shown in Configuration File section.

    +
  • +
  • +

    When you update a config map with service.json - settings are applied immediately without Moon restart.

    +
  • + + +
    +

    2.6.3. Adjusting Timeouts

    -

    | Time | 2017/11/01 19:12:42 | - -| Status | [SESSION_ATTEMPTED] | See table below for complete list of statuses. -| Additional fields | [firefox-45.0] | One or more sections showing additional information such as browser name, user name, IP address or error message -| Attempt number | [1] | For SESSION_ATTEMPTED or SESSION_CREATED entries means current attempt number. For SESSION_CREATED entries means total number of attempts to create this session. -| Duration | [4.15s] | For some log entries this field shows how much time operation took

    +

    Sometimes things go wrong: user can unexpectedly disconnect or browser session starts longer than needed. This can lead to overall cluster degradation because of broken browser pods occupying all available hardware. To prevent such cases Moon automatically detects and closes suspicious browser sessions. Several flags allow to adjust timeout settings:

    +-++++ + + + + + + + + - + + + + + + + + + +
    Table 3. Available Timeout Flags
    FlagDefault ValueMeaningNotes

    The following statuses are available:

    -

    .Log entry statuses

    -timeout

    1 minute

    Maximum browser session idle time - measured as maximum time between separate HTTP requests corresponding to a running session.

    When this timeout expires - session is automatically closed. You may need to increase this timeout when tested application pages load too slowly.

    -session-attempt-timeout

    10 minutes

    Maximum time to start browser pod.

    This time includes Kubernetes scheduling time and browser image download duration.

    -
    -

    | Status | Description

    -
    -
    -

    | AWAITING_SERVICE | Waiting for Kubernetes service to start -| BAD_REQUEST | Failed to process user request -| BAD_RESOURCES | User incorrectly configured browser container resources -| BAD_SCREEN_RESOLUTION | User requested to set wrong custom screen resolution -| BAD_TIMEZONE | User requested to set wrong custom time zone inside container -| BAD_TIMEOUT | User requested to set wrong session timeout -| BAD_VIDEO_FRAME_RATE | User requested to capture video with wrong frame rate -| BAD_VIDEO_SCREEN_SIZE | User requested to capture video with wrong screen size -| CLIENT_DISCONNECTED | User disconnected and session was interrupted -| CREATING_POD | Starting to create pod with browser -| CREATING_SERVICE | Starting to create service for browser session -| DELETING_POD | Starting to delete pod with browser -| DELETING_SERVICE | Starting to delete service for browser session -| DELETING_SESSION | Received request to delete browser session -| EMPTY_REQUEST | Received empty request from user -| FAILED_TO_CREATE_POD | Failed to create browser pod -| FAILED_TO_CREATE_SERVICE | Failed to create browser service -| FAILED_TO_DELETE_POD | Failed to delete browser pod -| FAILED_TO_DELETE_SERVICE | Failed to delete browser service -| FAILED_TO_DELETE_SESSION | Failed to delete browser session -| FAILED_TO_GET_LOGS | Failed to get session logs -| FORBIDDEN_TO_CREATE_POD | Kubernetes return forbidden status when creating pod -| INIT | Service initialization messages -| LOGS | Requested session logs -| LOGS_CLIENT_DISCONNECTED | Client disconnected while streaming session logs -| MALFORMED_VOLUME | Moon skipped malformed volume specification from browsers.json -| POD_CREATED | Browser pod created -| POD_DELETED | Browser pod deleted -| PROXYING | Proxying requests to specified URL -| PROXY_ERROR | Failed to proxy requests to specified URL -| SERVER_ERROR | Failed to create pod or service due to internal server error (probably a bug) -| SERVICE_CREATED | Browser service created -| SERVICE_DELETED | Browser service deleted -| SERVICE_IS_UP | Browser service successfully started -| SESSION_CREATED | Browser session successfully created -| SESSION_DELETED | Session successfully deleted -| SESSION_FAILED | Failed to create new session -| SESSION_TIMED_OUT | Existing session timed out -| SESSION_NOT_FOUND | Received request with empty session ID -| SHUTTING_DOWN | Shutting down the service -| STATUS_ERROR | Failed to refresh Moon status -| STATUS_REQUEST | Received Moon status request -| STATUS_REQUEST_ERROR | Failed to return Moon status -| UNSUPPORTED_BROWSER | User requested unsupported browser -| USER_NOT_FOUND | Trying to request session with unknown user -| VNC_CLIENT_DISCONNECTED | User disconnected while proxying VNC traffic -| VNC_ERROR | An error occurred while proxying VNC traffic -| VNC_SESSION | User requested VNC session -| VNC_SESSION_CLOSED | User closed VNC session

    - --- - +
    +

    2.6.4. Adjusting Resources Consumption

    +
    +
    - + + -

    :leveloffset: 1 -:leveloffset: +1

    -

    == CLI Flags -These flags should be specified in Kubernetes YAML files when starting the cluster.

    -

    The following flags are supported by moon: -` --config-file string - optional configuration file (default "config/service.json") --cpu-limit string - browser container cpu limit (default "1") --cpu-request string - browser container cpu request (default "0.5") --credentials-dir string - directory where credentials are mounted (default "credentials") --grace-period duration - graceful shutdown (default 30s) --guest-user string - guest quota user name (default "browsers") --license-file string - path to license file (default "license/license.key") --listen string - address to bind (default ":4444") --memory-limit string - browser container memory limit (default "1Gi") --memory-request string - browser container memory request (default "512Mi") --namespace string - namespace --quota-dir string - quota directory (default "quota") --session-attempt-timeout duration - new session attempt timeout (default 30m0s) --timeout duration - override session timeout (default 1m0s) --users-file string - path to users file (default "users/users.htpasswd") --version - show version and exit -`

    -

    :leveloffset: 1

    -

    == Advanced Features -:leveloffset: +1

    -

    == Special Capabilities

    -

    Moon supports a set of custom capabilities. You can pass them in tests to enable or disable some features.

    -

    === Live Browser Screen: enableVNC

    -

    Moon supports showing browser screen during test execution. To see browser screen add capability:

    -

    .Type: boolean ----- -enableVNC: true -----

    -

    Browser screen will be shown in Selenoid UI.

    -

    === Custom Screen Resolution: screenResolution

    -

    Moon allows you to set custom screen resolution in containers being run:

    -

    .Type: string, format: <width>x<height> ----- -screenResolution: "1280x1024" -----

    -

    You can optionally add colors depth:

    -

    .Type: string, format: <width>x<height>x<colors-depth> ----- -screenResolution: "1280x1024x24" -----

    -

    [WARNING] -==== -This capability sets only screen resolution - not browser window size. -Most of browsers have some default window size value this is why your screenshot size can be smaller than screen resolution specified in capability. -You should manually resize window to desired width and height or use Selenium maximize operation. -====

    -

    === Video Recording: enableVideo, videoName, videoScreenSize, videoFrameRate, videoCodec

    -

    To enable video recording for session, add:

    -

    .Type: boolean ----- -enableVideo: true -----

    -

    * By default saved video files are named <session-id>.mp4 where <session-id> is a unique identifier of Selenium session. -To provide custom video name specify: -+ -.Type: string ----- -videoName: "my-cool-video.mp4" ----- -+ -WARNING: It is important to add mp4 file extension.

    -

    * By default the entire screen picture is being recorded. -Specifying screenResolution capability changes recorded video size (width and height) accordingly. -You can override video screen size by passing a capability. In case of videoScreenSize -resolution is less than actual, screen on video will be trimmed starting from top-left corner: -+ -.Type: string ----- -videoScreenSize: "1024x768" -----

    -

    * Default video frame rate is 12 frames per second. Specifying videoFrameRate capability changes this value: -+ -.Type: int ----- -videoFrameRate: 24 -----

    -

    * By default Moon is using libx264 codec for video output. If this codec is consuming too much CPU, you can change it using videoCodec capability: -+ -.Type: string ----- -videoCodec: "mpeg4" -----

    -

    === Custom Test Name: name

    -

    For debugging purposes it is often useful to give a distinct name to every test case. You can set test case name by passing the following capability:

    -

    .Type: string ----- -name: "myCoolTestName" -----

    -

    The main application of this capability - is debugging tests in the UI which is showing specified name for every running session.

    -

    === Per-session Time Zone: timeZone

    -

    Some tests require particular time zone to be set in operating system.

    -

    .Type: string ----- -timeZone: "Europe/Moscow" -----

    -

    You can find most of available time zones here. -Without this capability launched browser containers will have Moon timezone.

    -

    === Per-session Environment Variables: env

    -

    Sometimes you may want to set some environment variables for every test case (for example to test with different default locales). To achieve this pass one more capability:

    -

    .Type: array, format: <key>=<value> ----- -env: ["LANG=ru_RU.UTF-8", "LANGUAGE=ru:en", "LC_ALL=ru_RU.UTF-8"] -----

    -

    Environment variables from this capability are appended to variables from configuration file.

    -

    === Hosts Entries: hostsEntries

    -

    Although you can configure a separate list of /etc/hosts entries for every browser image in Browsers List sometimes you may need to add more entries for particular test cases. This can be easily achieved with:

    -

    .Type: array, format: <hostname>:<ip-address> ----- -hostsEntries: ["example.com:192.168.0.1", "test.com:192.168.0.2"] -----

    -

    Entries from this capability will be override /etc/hosts entries from browsers list file.

    -

    === Custom Session Timeout: sessionTimeout

    -

    Sometimes you may want to change idle timeout for selected browser session. To achieve this - pass the following capability:

    -

    .Type: int ----- -sessionTimeout: 1m30s -----

    -

    Timeout is always specified in Golang duration format, e.g. 30s or 2m or 1h and so on.

    -

    === Specifying Capabilities via Protocol Extensions

    -

    Some Selenium clients allow passing only a limited number of capabilities specified in WebDriver specification. For such cases Moon supports reading capabilities using WebDriver protocol extensions feature. The following two examples deliver the same result. Usually capabilities are passed like this:

    -

    .Passing Capabilities as Usually ----- -{"browserName": "firefox", "version": "62.0", "screenResolution": "1280x1024x24"} -----

    -

    Moon is using moon:options key to read protocol extension capabilities:

    -

    .Passing Capabilities using Protocol Extensions ----- -{"browserName": "firefox", "version": "62.0", "moon:options": {"screenResolution": "1280x1024x24"}} -----

    -

    :leveloffset: 1 -:leveloffset: +1

    -

    == Accessing Files Downloaded with Browser

    -

    NOTE: Files are accessible only when browser session is running.

    -

    Your tests may need to download files with browsers. To analyze these files a common requirement is then to somehow extract downloaded files from browser containers. Moon provides a /download API dramatically simplifying downloading such files. To work with it:

    -

    . Start a new session, for example with ID firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840. -. In tests code save all files to ~/Downloads directory. -. Access all downloaded files using an URL: -+ -` -http://moon-host.example.com:4444/download/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/myfile.txt -` -. Close the session

    -

    :leveloffset: 1 -:leveloffset: +1

    -

    == Accessing Clipboard

    -

    NOTE: Clipboard is accessible only when browser session is running.

    -

    Sometimes you may need to interact with the clipboard to check that your application copy-paste feature works. Moon has a dedicated API to interact with the clipboard. To use it:

    -

    . Start a new session, for example with ID firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840. -. To get clipboard value send the following HTTP request: -+ -` -$ curl http://moon-host.example.com:4444/clipboard/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840

    -

    some-clipboard-value -` -. To update clipboard value: -+ -` -$ curl -X POST --data 'some-clipboard-value' http://moon-host.example.com:4444/clipboard/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840 -`

    -

    :leveloffset: 1

    -

    == License Agreement

    -

    Last updated January 5th, 2018. Replaces the prior version in its entirety.

    -

    This is a legal agreement. By downloading, installing, copying, saving on Customer’s computer, or otherwise using Aerokube software, support or products Customer becomes a party to this Agreement and Customer consents to be bound by all the terms and conditions set forth below.

    -

    . Parties

    -

    .. "Aerokube", "Licensor" or "We" means Aerokube OÜ, having its principal place of business at Narva mnt 7-123, Tallinn city, Harju county, 10117, Estonia, registered in the Commercial Register of Estonia, registry code: 12345678.

    -

    .. "Customer", "Licensee" or "You" means the sole proprietor or legal entity specified in the Subscription Confirmation. For legal entities, "Customer" includes any entity which controls, is controlled by, or is under common control with Customer. For the purposes of this definition, "control" means one of the following:

    -

    …​ The power, directly or indirectly, to direct or manage such entity, whether by contract or otherwise. -…​ Ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity.

    -

    . Definitions

    -

    .. "Agreement" means this License Agreement.

    -

    .. "Product" means any generally available Licensor’s software product identified by Licensor as a software developer tool. For the avoidance of doubt, the Product is not produced to the specifications of Customer nor customized through modification or personalization, is intended for mass distribution, and no software code will be provided to Customer.

    -

    .. "User" means any employee, independent contractor or other personnel obtaining access to the Product(s) from Customer.

    -

    .. "Number of Concurrent Sessions" means maximum number of software testing processes being run using the Product in parallel. This can be for example browsers executing User’s tests.

    -

    .. "License Key" means a unique key-code that enables a Licensee to use the Product by unlocking the fixed Number of Concurrent Sessions. Only Licensor and/or its representatives are permitted to produce License Keys for the Product.

    -

    .. "Subscription" means an arrangement for making use of the Product of periodic nature on a prepayment plan. For the purpose of clarity, Subscription includes the subscription term, Products provided to Customer, subscription fees, payment schedules and fixed number of License Keys.

    -

    .. "Product Evaluation" means using the Product without a valid License Key.

    -

    .. "Subscription Confirmation" means an email confirming Customer’s rights to access and use Products, including total Number of Concurrent Sessions.

    -

    .. "Product Installation" means a Product copy running on Customer’s computer device, hardware server or virtual machine.

    -

    .. "Product Version" means a release, update, or upgrade of a particular Product that is not identified by Licensor as being made for the purpose of fixing software bugs.

    -

    .. "Bug Fix Update" for a particular Product Version means a software update or release that is specifically identified by Licensor as a bug fix for that Product Version.

    -

    .. "Fallback Date" means the date that was 12 months prior to the date of expiration of the Subscription.

    -

    .. "Fallback Version" means the most recent Product Version that Licensor made available for public purchase prior to the Fallback Date, along with any Bug Fix Updates for that Product Version. For the purpose of clarity, Fallback Version does not include any Product updates or upgrades other than Bug Fix Updates that Customer may have used in the period between the Fallback Date and the date of expiration of the Subscription.

    -

    .. "E-mail Support" means a form of customer support provided by the Licensor. At the time of writing, the corresponding e-mail address is support@aerokube.com; should the address be changed, the new address will be referred to on the Licensor’s web site.

    -

    .. "Instant Messaging Support" means a form of customer support provided by the Licensor. At the time of writing, the corresponding address to support channel is https://t.me/aerokube_moon; should the address be changed, the new address will be referred to on the Licensor’s web site.

    -

    .. "Affiliate" means any entity belonging to the same group as the Licensor.

    -

    . How this Agreement Works

    -

    .. Entire Agreement. This Agreement, including the Third-Party Software license terms, constitutes the entire agreement between the parties concerning its subject matter and supersedes any prior agreements between Customer and Licensor regarding Customer’s use of any Products. No purchase order, other ordering document or any handwritten or typewritten text which purports to modify or supplement the printed text of this Agreement or any schedule will add to or vary the terms of this Agreement unless signed by both Customer and Licensor.

    -

    .. Reservation of Rights. Aerokube reserves the right at any time to cease the support of the Product and to alter prices, features, specifications, capabilities, functions, terms of use, release dates, general availability or other characteristics of the Product.

    -

    .. Changes to this Agreement. We may update or modify this Agreement from time to time, including any referenced policies and other documents. If a revision meaningfully reduces Customer’s rights, we will use reasonable efforts to notify Customer. If we modify this Agreement, the modified version of the Agreement will be effective from the start of the next Subscription term. In this case, if Customer objects to the updated Agreement terms, as Customer’s exclusive remedy, Customer may cancel the Subscription. Customer may be required to click through the updated Agreement to show its acceptance. For the avoidance of doubt, each Subscription Confirmation is subject to the version of the Agreement in effect on the Subscription Confirmation date.

    -

    .. Opportunity to Review. Customer hereby declares that Customer has had sufficient opportunity to review this Agreement, understand the content of all of its clauses, negotiate its terms, and seek independent professional legal advice in that respect before entering into it. Consequently, any statutory "form contract" ("adhesion contract") regulations shall not be applicable to this Agreement.

    -

    .. Severability. If a particular term of this Agreement is not enforceable, the unenforceability of that term will not affect any other terms of this Agreement.

    -

    .. Headings. Headings and titles are for convenience only and do not affect the interpretation of this Agreement.

    -

    .. No Waiver. Our failure to enforce or exercise any part of this Agreement is not a waiver of that section.

    -

    .. Notice. Aerokube may deliver any notice to Customer via electronic mail to an email address provided by Customer, registered mail, personal delivery or renowned express courier (such as DHL, FedEx or UPS). Any such notice will be deemed to be effective:

    -

    …​ On the day the notice is sent to Customer via email. -…​ Upon personal delivery. -…​ One (1) day after deposit with an express courier or five (5) days after deposit in the mail, whichever occurs first.

    -

    .. Governing Law. This Agreement will be governed by the laws of the Estonia, without reference to conflict of laws principles. Customer agrees that any litigation relating to this Agreement may only be brought in, and will be subject to the jurisdiction of, any competent court of the Estonia. The parties agree that the United Nations Convention on Contracts for the International Sale of Goods does not apply to this Agreement.

    -

    .. Exceptions or Modifications. For exceptions or modifications to this Agreement, please contact Aerokube at: support@aerokube.com In case the terms of this Agreement are in conflict with the terms of any agreement individually negotiated and agreed between Aerokube and Customer, the terms of the latter shall prevail.

    -

    .. Force Majeure. Except with respect to Customer’s payment obligations, neither party shall be liable to the other for any delay or failure to perform any obligation under this Agreement (except for a failure to pay fees) if the delay or failure is due to unforeseen events which occur after the signing of this Agreement and which are beyond the reasonable control of such party ("Force Majeure Event"), such as a strike, blockade, war, act of terrorism, riot, natural disaster, failure or diminishment of power or telecommunications or data networks or services, or refusal of a license by a government agency. In the event of a Force Majeure Event that prevents one part from substantially performing its obligations hereunder for a period of ten (10) days or more, either party may terminate this Agreement on five (5) days written notice.

    -

    . Grant of Rights

    -

    .. The Product include code and libraries licensed to Licensor by third parties, including open source software.

    -

    .. The Product is provided basing on the Number of Concurrent Sessions. If Customer complies with the terms of this Agreement, Customer has the rights stipulated hereunder for each Subscription that Customer acquires. Customer’s rights acquired in relation to the Product are limited to those necessary to enable Customer and its Users to effectively operate the Product(s). All other rights remain reserved to Licensor.

    -

    .. Unless the Subscription has expired or this Agreement is terminated in accordance with respective section, and subject to the terms and conditions specified herein, Licensor grants Customer a non-exclusive and non-transferable right to use each Product covered by the Subscription as stipulated below.

    -

    .. Customer may:

    -

    …​ For each License Key included to Subscription have one Product Installation of any version covered by the Subscription on any operating system supported by the Product.

    -

    …​ Make one backup copy of the Product solely for archival/security backup purposes.

    -

    .. Customer may not:

    -

    …​ Allow the same Product Installation to be used concurrently by more than the Number of Concurrent Sessions specified for used License Key in Subscription Confirmation.

    -

    …​ Rent, lease, reproduce, modify, adapt, create derivative works of, distribute, sell, or transfer the Product.

    -

    …​ Provide access to the Product or the right to use the Product to a third party.

    -

    …​ Reverse engineer, decompile, disassemble, modify, translate, make any attempt to discover the source code of the Product.

    -

    …​ Remove or obscure any proprietary or other notices contained in the Product.

    -

    .. Following the expiration of this Agreement, the rights stipulated in "Grant of Rights" section shall continue on a perpetual, royalty-free, non-exclusive, and non-transferable basis for the continued use of a Fallback Version of each Product covered by the Subscription. The limitations set forth in this section apply to the usage of the Fallback Version. The rights granted in this section are expressly contingent upon Customer not being in breach of this Agreement, including having paid in full the applicable Subscription fees for the preceding 12 months or longer without interruption.

    -

    .. Customer acknowledges that no ownership right is conveyed to Customer under this Agreement, irrespective of the use of terms such as "purchase" or "sale". Licensor has and retains all rights, title and interest, including all intellectual property rights, in and to the Products and any and all related or underlying technology, and any modifications or derivative works thereof, including without limitation as they may incorporate Feedback (as defined below).

    -

    .. This Agreement applies whether Customer purchases a Subscription directly from Licensor or through resellers. If Customer purchases through a reseller, the Subscription details shall be as stated in the Subscription Confirmation issued by the reseller to Customer, and the reseller is responsible for the accuracy of any such Subscription Confirmation. Resellers are not authorized to make any promises or commitments on Licensor behalf, and Customer understands and agrees that Licensor is not bound by any obligations to Customer other than as specified in this Agreement.

    -

    . Access to Products

    -

    .. All deliveries under this Agreement will be electronic. Customer and its Users must have an Internet connection in order to receive any deliveries. For the avoidance of doubt, Customer is responsible for downloading and installing the Products. Download instructions are made available on Licensor website at http://aerokube.com.

    -

    .. Customer enables full access to Product Installation by specifying a License Key from Subscription Confirmation.

    -

    .. Subject to the terms of this Agreement, Customer is granted a right to install and use the Product for evaluation purposes without charge for unlimited amount of time. The Product contains a feature that will automatically limit allowed Number of Concurrent Sessions. Licensor reserves the right at any time to change that limit in new Product versions.

    -

    . Fees

    -

    .. Customer shall pay its Subscription fees in accordance with Licensor Terms of Purchase or the reseller’s terms of purchase, whichever are applicable.

    -

    .. The Subscription fees shall be paid in full, and any levies, duties and/or taxes imposed by Customer’s jurisdiction (including, but not limited to, value added tax, sales tax and withholding tax), shall be borne solely by Customer.

    -

    .. Customer may not deduct any amounts from fees payable to Licensor or the reseller, unless otherwise specified in the applicable terms of purchase.

    -

    . Feedback

    -

    .. Customer has no obligation to provide Licensor with ideas, suggestions, or proposals ("Feedback"). -.. If Customer or Users submit Feedback to Licensor, then Customer grants Licensor a non-exclusive, worldwide, royalty-free license that is sub-licensable and transferable, to make, use, sell, have made, offer to sell, import, reproduce, publicly display, distribute, modify, or publicly perform the Feedback in any manner without any obligation, royalty or restriction based on intellectual property rights or otherwise.

    -

    . LIMITED WARRANTY -+ -ALL PRODUCTS ARE PROVIDED TO CUSTOMER ON AN "AS IS" AND "AS AVAILABLE" BASIS WITHOUT WARRANTIES. USE OF THE PRODUCTS IS AT YOUR OWN RISK. AEROKUBE MAKES NO WARRANTY AS TO THEIR USE OR PERFORMANCE. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, AEROKUBE, AND ITS SUPPLIERS (WHICH SHALL INCLUDE THE PROVIDERS OF THE THIRD PARTY SOFTWARE) AND RESELLERS, DISCLAIM ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, WITH REGARD TO THE PRODUCTS, AND THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES CUSTOMER SPECIFIC LEGAL RIGHTS. CUSTOMER MAY HAVE OTHER RIGHTS, WHICH VARY FROM STATE/JURISDICTION TO STATE/JURISDICTION. AEROKUBE (AND ITS AFFILIATES, AGENTS, DIRECTORS AND EMPLOYEES) DOES NOT WARRANT:

    -

    .. THAT THE PRODUCTS ARE ACCURATE, RELIABLE OR CORRECT - .. THAT THE PRODUCTS WILL MEET YOUR REQUIREMENTS - .. THAT THE PRODUCTS WILL BE AVAILABLE AT ANY PARTICULAR TIME OR LOCATION, UNINTERRUPTED OR SECURE - .. THAT ANY DEFECTS OR ERRORS WILL BE CORRECTED - .. THAT THE PRODUCTS ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS

    -

    + -ANY CONTENT OR DATA DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE PRODUCTS ARE DOWNLOADED AT YOUR OWN RISK AND YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR PROPERTY OR LOSS OF DATA THAT RESULTS FROM SUCH DOWNLOAD. NO WARRANTY OR LIABILITY AT ALL IS GIVEN TO PRODUCTS UNDER EVALUATION.

    -

    . DISCLAIMER OF DAMAGES

    -

    .. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL AEROKUBE (OR ITS AFFILIATES, AGENTS, DIRECTORS, OR EMPLOYEES), OR AEROKUBE LICENSORS, SUPPLIERS OR RESELLERS BE LIABLE TO CUSTOMER OR ANYONE ELSE FOR: -+ -…​ ANY LOSS OF USE, DATA, GOODWILL, OR PROFITS, WHETHER OR NOT FORESEEABLE -…​ ANY LOSS OR DAMAGES IN CONNECTION WITH TERMINATION OR SUSPENSION OF CUSTOMER’S ACCESS TO OUR PRODUCTS IN ACCORDANCE WITH THIS AGREEMENT -…​ ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, EXEMPLARY OR PUNITIVE DAMAGES WHATSOEVER (EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF THESE DAMAGES), INCLUDING THOSE: -+ -…​. RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER OR NOT FORESEEABLE -…​. BASED ON ANY THEORY OF LIABILITY, INCLUDING BREACH OF CONTRACT OR WARRANTY, STRICT LIABILITY, NEGLIGENCE OR OTHER TORTIOUS ACTION -…​. ARISING FROM ANY OTHER CLAIM ARISING OUT OF OR IN CONNECTION WITH CUSTOMER’S USE OF OR ACCESS TO THE PRODUCTS OR SUPPORT.

    -

    .. THE FOREGOING LIMITATION OF LIABILITY SHALL APPLY TO THE FULLEST EXTENT PERMITTED BY LAW IN THE APPLICABLE JURISDICTION.

    -

    .. OUR TOTAL LIABILITY IN ANY MATTER ARISING OUT OF OR IN RELATION TO THIS AGREEMENT IS LIMITED TO ONE HUNDRED (100) US DOLLARS OR THE AGGREGATE AMOUNT PAID OR PAYABLE BY THE CUSTOMER FOR PRODUCTS DURING THE THREE-MONTH PERIOD PRECEDING THE EVENT GIVING RISE TO THE LIABILITY, WHICHEVER IS GREATER. THIS LIMITATION WILL APPLY EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF LIABILITY EXCEEDING SUCH AMOUNT AND NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.

    -

    . Term and Termination

    -

    .. The term of this Agreement will commence upon acceptance of this Agreement by Customer as set forth in the preamble above, and will continue for each Product through the end of the applicable subscription period specified in the respective Subscription Confirmation. This Agreement will automatically renew with respect to each Product for a successive subscription term, unless terminated as set forth herein.

    -

    .. Customer may terminate this Agreement at any time by cancelling its Product subscription. If such termination occurs during a then-current subscription period, this Agreement will continue to be effective until the end of that subscription period. Such termination does not relieve Customer of the obligation to pay any outstanding subscription fees owed to Licensor, and no credits or refunds will be issued to Customer for prepaid subscription fees (except as specified in the Licensor Terms of Purchase, if applicable).

    -

    .. Licensor may terminate this agreement if:

    -

    …​ Customer has materially breached this Agreement and fails to cure such breach within thirty (30) days of written notice thereof.

    -

    …​ Customer fails to make the timely payment of subscription fees in accordance with "Fees" Section of this Agreement.

    -

    …​ Licensor is required to do so by law (for example, where the provision of the Product to Customer is, or becomes, unlawful).

    -

    …​ Licensor elects to discontinue providing the Product, in whole or in part.

    -

    .. Licensor will make reasonable efforts to notify Customer via email as follows:

    -

    …​ Thirty (30) days prior to termination of the Agreement when required to terminate by law or because of discontinued Product. In such events Customer will be entitled to a refund of the unused portion of prepaid subscription fees, if applicable.

    -

    …​ Three (3) days prior to termination of the Agreement in other cases. In such events Customer will not be entitled to any refund of the unused portion of prepaid subscription fees.

    -

    .. Survival. Upon the expiration or termination of this Agreement by Customer and if Customer elects to use the Fallback Version of the Product this Agreement statements will also survive with respect to said Fallback Version.

    -

    . Temporary Suspension for Non-payment

    -

    . Licensor reserves the right to suspend or limit Customer’s access to Aerokube Products if Customer fails to pay subscription fees on time.

    -

    . If Licensor suspends or limits Customer’s access to Aerokube Products for non-payment according, Customer must pay all past due amounts in order to restore full access to Aerokube Products.

    -

    . Customer hereby agrees that Licensor is entitled to charge Customer for the time period during which Customer has access to Aerokube Products until Customer or Licensor terminates or suspends Customer’s subscription in accordance with this Agreement.

    -

    . Export Regulations -+ -Customer shall comply with all applicable laws and regulations with regards to economic sanctions, export controls, import regulations, and trade embargoes (all herein referred to as "Sanctions"), including those of the European Union and United States (specifically the Export Administration Regulations (EAR)). Customer declares that it is not a person targeted by Sanctions nor is it otherwise owned or controlled by or acting on behalf of any person targeted by Sanctions. Further, Customer warrants that it will not download or otherwise export or re-export the Product or any related technical data directly or indirectly to any person targeted by Sanctions or download or otherwise use the Product for any end-use prohibited or restricted by Sanctions.

    -

    . Customer Support

    -

    .. Licensor provides Email Support as well as Instant Messaging Support. The response time will be reasonable, but no specific response time guarantees are given.

    -

    .. Customer may request additional paid support from Licensor which is subject of a supplementary individually negotiated Agreement between Customer and Licensor.

    -

    .. Any guarantees of support availability only apply to the latest version of Licensed Software available in Customer Subscription.

    -

    . Customer Data

    -

    .. Use of Name and Logo. Customer agrees that Licensor may identify it as a customer of Aerokube and may refer to it by name, trade name and trademark, if applicable. Licensor may also briefly describe Customer’s business in Licensor marketing materials, on the Aerokube website and/or in public or legal documents. Customer hereby grants Licensor a worldwide, non-exclusive and royalty-free license to use Customer’s name and any of Customer’s trade names and trademarks solely pursuant to this marketing section.

    -

    .. Gathering of Usage Statistics. Customer acknowledges and agrees that the Product may contain a feature that reports the usage statistics, diagnostics information and usage meta-information of the Product back to the Licensor. Customer may opt out of the gathering of usage statistics by turning off this feature in the Product settings.

    -

    [appendix] -== Pricing

    -

    . Moon price is calculated using so-called Number of Concurrent Sessions that is to say total number of browser sessions being run in parallel. We control this by limiting total number of simultaneously running browser pods to the value you are purchasing. -. When no license key is provided 4 (four) parallel browser sessions maximum are allowed. If such limit is sufficient for you - you are allowed use Moon without license key for unlimited period of time. -. If free limit is insufficient - you need a paid license. Such license can include any desired number of parallel browser sessions (yes, even 42). -. Every parallel session has a fixed cost - $5 USD (five United States dollars). -+ -.An example price calculation ----- -42 sessions * $5/month = $210/month ----- -. For simplicity we calculated monthly prices for some frequent cases:

    -

    .Moon License Pricing

    + + +Flags and fields described in this section apply to browser container consumption only. Other system containers started in browser pod have reasonable fixed values assigned. +
    -
    -

    | Number of Parallel Sessions | Price per Month, USD

    -

    | 0-4 | free -| 5 | $25 -| 10 | $50 -| 15 | $75 -| 20 | $100 -| 25 | $125 -| 30 | $150 -| 40 | $200 -| 50 | $250 -| 75 | $375 -| 100 | $500 -| 150 | $750 -| 200 | $1000 -| 250 | $1250 -| 500 | $2500 -| 750 | $2750 -| 1000 | $5000

    +

    Moon has reasonable defaults for resources consumed by every browser pod. Sometimes you may need to override these settings. To override resource settings globally for every browser image use one of the following flags:

    +-+++ + + + + + + + - + + + + + + + + + + + + + + + + + +
    Table 4. Resources Consumption Flags
    FlagDefault ValueMeaning

    [appendix] -== Example Configuration Files

    -

    .Example moon-sessions.yaml file contents -[source,yaml] ----- -apiVersion: v1 -kind: ResourceQuota -metadata: - name: max-moon-sessions -spec: - hard: - pods: "6" ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: moon-rbac -subjects: - - kind: ServiceAccount - name: default - namespace: default -roleRef: - kind: ClusterRole - name: cluster-admin - apiGroup: rbac.authorization.k8s.io ----- -.Example moon.yaml file contents -[source,yaml] ----- -kind: Service -apiVersion: v1 -metadata: - name: moon -spec: - selector: - app: moon - ports: - - protocol: TCP - port: 4444 - type: NodePort ---- -apiVersion: apps/v1beta1 -kind: Deployment -metadata: - name: moon -spec: - replicas: 1 - template: - metadata: - labels: - app: moon - spec: - containers: - - name: moon - image: aerokube/moon:1.3.1 - resources: - limits: - cpu: "1" - memory: "512Mi" - requests: - cpu: "0.25" - memory: "64Mi" - ports: - - containerPort: 4444 - volumeMounts: - - name: quota - mountPath: /quota - readOnly: true - - name: users - mountPath: /users - readOnly: true - volumes: - - name: quota - configMap: - name: quota - - name: users - secret: - secretName: users ----- -.Example moon-api.yaml file contents -[source,yaml] ----- -kind: Service -apiVersion: v1 -metadata: - name: moon-api -spec: - selector: - app: moon-api - ports: - - protocol: TCP - port: 8080 - type: NodePort ---- -apiVersion: apps/v1beta1 -kind: Deployment -metadata: - name: moon-api -spec: - replicas: 1 - template: - metadata: - labels: - app: moon-api - spec: - containers: - - name: moon-api - image: aerokube/moon-api:1.3.1 - resources: - limits: - cpu: "0.25" - memory: "128Mi" - requests: - cpu: "0.1" - memory: "64Mi" - ports: - - containerPort: 8080 - volumeMounts: - - name: quota - mountPath: /quota - volumes: - - name: quota - configMap: - name: quota - - name: users - secret: - secretName: users ----- -.Example browsers.json file contents -[source,json] ----- -{ - "firefox": { - "default": "58.0", - "versions": { - "58.0": { - "image": "selenoid/vnc:firefox_58.0", - "port": "4444", - "path": "/wd/hub" - }, - "57.0": { - "image": "selenoid/vnc:firefox_57.0", - "port": "4444", - "path": "/wd/hub" - }, - "56.0": { - "image": "selenoid/vnc:firefox_56.0", - "port": "4444", - "path": "/wd/hub" - }, - "55.0": { - "image": "selenoid/vnc:firefox_55.0", - "port": "4444", - "path": "/wd/hub" - }, - "54.0": { - "image": "selenoid/vnc:firefox_54.0", - "port": "4444", - "path": "/wd/hub" - }, - "53.0": { - "image": "selenoid/vnc:firefox_53.0", - "port": "4444", - "path": "/wd/hub" - }, - "52.0": { - "image": "selenoid/vnc:firefox_52.0", - "port": "4444", - "path": "/wd/hub" - }, - "51.0": { - "image": "selenoid/vnc:firefox_51.0", - "port": "4444", - "path": "/wd/hub" - }, - "50.0": { - "image": "selenoid/vnc:firefox_50.0", - "port": "4444", - "path": "/wd/hub" - }, - "49.0": { - "image": "selenoid/vnc:firefox_49.0", - "port": "4444", - "path": "/wd/hub" - }, - "48.0": { - "image": "selenoid/vnc:firefox_48.0", - "port": "4444", - "path": "/wd/hub" - }, - "47.0": { - "image": "selenoid/vnc:firefox_47.0", - "port": "4444", - "path": "/wd/hub" - }, - "46.0": { - "image": "selenoid/vnc:firefox_46.0", - "port": "4444", - "path": "/wd/hub" - }, - "45.0": { - "image": "selenoid/vnc:firefox_45.0", - "port": "4444", - "path": "/wd/hub" - }, - "44.0": { - "image": "selenoid/vnc:firefox_44.0", - "port": "4444", - "path": "/wd/hub" - }, - "43.0": { - "image": "selenoid/vnc:firefox_43.0", - "port": "4444", - "path": "/wd/hub" - }, - "42.0": { - "image": "selenoid/vnc:firefox_42.0", - "port": "4444", - "path": "/wd/hub" - }, - "41.0": { - "image": "selenoid/vnc:firefox_41.0", - "port": "4444", - "path": "/wd/hub" - }, - "40.0": { - "image": "selenoid/vnc:firefox_40.0", - "port": "4444", - "path": "/wd/hub" - }, - "39.0": { - "image": "selenoid/vnc:firefox_39.0", - "port": "4444", - "path": "/wd/hub" - }, - "38.0": { - "image": "selenoid/vnc:firefox_38.0", - "port": "4444", - "path": "/wd/hub" - }, - "37.0": { - "image": "selenoid/vnc:firefox_37.0", - "port": "4444", - "path": "/wd/hub" - }, - "36.0": { - "image": "selenoid/vnc:firefox_36.0", - "port": "4444", - "path": "/wd/hub" - }, - "35.0": { - "image": "selenoid/vnc:firefox_35.0", - "port": "4444", - "path": "/wd/hub" - }, - "34.0": { - "image": "selenoid/vnc:firefox_34.0", - "port": "4444", - "path": "/wd/hub" - }, - "33.0": { - "image": "selenoid/vnc:firefox_33.0", - "port": "4444", - "path": "/wd/hub" - }, - "32.0": { - "image": "selenoid/vnc:firefox_32.0", - "port": "4444", - "path": "/wd/hub" - }, - "31.0": { - "image": "selenoid/vnc:firefox_31.0", - "port": "4444", - "path": "/wd/hub" - }, - "30.0": { - "image": "selenoid/vnc:firefox_30.0", - "port": "4444", - "path": "/wd/hub" - }, - "29.0": { - "image": "selenoid/vnc:firefox_29.0", - "port": "4444", - "path": "/wd/hub" - }, - "28.0": { - "image": "selenoid/vnc:firefox_28.0", - "port": "4444", - "path": "/wd/hub" - }, - "27.0": { - "image": "selenoid/vnc:firefox_27.0", - "port": "4444", - "path": "/wd/hub" - }, - "26.0": { - "image": "selenoid/vnc:firefox_26.0", - "port": "4444", - "path": "/wd/hub" - }, - "25.0": { - "image": "selenoid/vnc:firefox_25.0", - "port": "4444", - "path": "/wd/hub" - }, - "24.0": { - "image": "selenoid/vnc:firefox_24.0", - "port": "4444", - "path": "/wd/hub" - }, - "23.0": { - "image": "selenoid/vnc:firefox_23.0", - "port": "4444", - "path": "/wd/hub" - }, - "22.0": { - "image": "selenoid/vnc:firefox_22.0", - "port": "4444", - "path": "/wd/hub" - }, - "21.0": { - "image": "selenoid/vnc:firefox_21.0", - "port": "4444", - "path": "/wd/hub" - }, - "20.0": { - "image": "selenoid/vnc:firefox_20.0", - "port": "4444", - "path": "/wd/hub" - }, - "19.0": { - "image": "selenoid/vnc:firefox_19.0", - "port": "4444", - "path": "/wd/hub" - }, - "18.0": { - "image": "selenoid/vnc:firefox_18.0", - "port": "4444", - "path": "/wd/hub" - }, - "17.0": { - "image": "selenoid/vnc:firefox_17.0", - "port": "4444", - "path": "/wd/hub" - }, - "16.0": { - "image": "selenoid/vnc:firefox_16.0", - "port": "4444", - "path": "/wd/hub" - }, - "15.0": { - "image": "selenoid/vnc:firefox_15.0", - "port": "4444", - "path": "/wd/hub" - }, - "14.0": { - "image": "selenoid/vnc:firefox_14.0", - "port": "4444", - "path": "/wd/hub" - }, - "13.0": { - "image": "selenoid/vnc:firefox_13.0", - "port": "4444", - "path": "/wd/hub" - }, - "12.0": { - "image": "selenoid/vnc:firefox_12.0", - "port": "4444", - "path": "/wd/hub" - }, - "11.0": { - "image": "selenoid/vnc:firefox_11.0", - "port": "4444", - "path": "/wd/hub" - }, - "10.0": { - "image": "selenoid/vnc:firefox_10.0", - "port": "4444", - "path": "/wd/hub" - }, - "9.0": { - "image": "selenoid/vnc:firefox_9.0", - "port": "4444", - "path": "/wd/hub" - }, - "8.0": { - "image": "selenoid/vnc:firefox_8.0", - "port": "4444", - "path": "/wd/hub" - }, - "7.0": { - "image": "selenoid/vnc:firefox_7.0", - "port": "4444", - "path": "/wd/hub" - }, - "6.0": { - "image": "selenoid/vnc:firefox_6.0", - "port": "4444", - "path": "/wd/hub" - }, - "5.0": { - "image": "selenoid/vnc:firefox_5.0", - "port": "4444", - "path": "/wd/hub" - }, - "4.0": { - "image": "selenoid/vnc:firefox_4.0", - "port": "4444", - "path": "/wd/hub" - }, - "3.6": { - "image": "selenoid/vnc:firefox_3.6", - "port": "4444", - "path": "/wd/hub" - } - } - }, - "chrome": { - "default": "65.0", - "versions": { - "65.0": { - "image": "selenoid/vnc:chrome_65.0", - "port": "4444" - }, - "64.0": { - "image": "selenoid/vnc:chrome_64.0", - "port": "4444" - }, - "63.0": { - "image": "selenoid/vnc:chrome_63.0", - "port": "4444" - }, - "62.0": { - "image": "selenoid/vnc:chrome_62.0", - "port": "4444" - }, - "61.0": { - "image": "selenoid/vnc:chrome_61.0", - "port": "4444" - }, - "60.0": { - "image": "selenoid/vnc:chrome_60.0", - "port": "4444" - }, - "59.0": { - "image": "selenoid/vnc:chrome_59.0", - "port": "4444" - }, - "58.0": { - "image": "selenoid/vnc:chrome_58.0", - "port": "4444" - }, - "57.0": { - "image": "selenoid/vnc:chrome_57.0", - "port": "4444" - }, - "56.0": { - "image": "selenoid/vnc:chrome_56.0", - "port": "4444" - }, - "55.0": { - "image": "selenoid/vnc:chrome_55.0", - "port": "4444" - }, - "54.0": { - "image": "selenoid/vnc:chrome_54.0", - "port": "4444" - }, - "53.0": { - "image": "selenoid/vnc:chrome_53.0", - "port": "4444" - }, - "52.0": { - "image": "selenoid/vnc:chrome_52.0", - "port": "4444" - }, - "51.0": { - "image": "selenoid/vnc:chrome_51.0", - "port": "4444" - }, - "50.0": { - "image": "selenoid/vnc:chrome_50.0", - "port": "4444" - }, - "49.0": { - "image": "selenoid/vnc:chrome_49.0", - "port": "4444" - }, - "48.0": { - "image": "selenoid/vnc:chrome_48.0", - "port": "4444" - } - } - }, - "opera": { - "default": "50.0", - "versions": { - "50.0": { - "image": "selenoid/vnc:opera_50.0", - "port": "4444" - }, - "49.0": { - "image": "selenoid/vnc:opera_49.0", - "port": "4444" - }, - "48.0": { - "image": "selenoid/vnc:opera_48.0", - "port": "4444" - }, - "47.0": { - "image": "selenoid/vnc:opera_47.0", - "port": "4444" - }, - "46.0": { - "image": "selenoid/vnc:opera_46.0", - "port": "4444" - }, - "45.0": { - "image": "selenoid/vnc:opera_45.0", - "port": "4444" - }, - "44.0": { - "image": "selenoid/vnc:opera_44.0", - "port": "4444" - }, - "43.0": { - "image": "selenoid/vnc:opera_43.0", - "port": "4444" - }, - "42.0": { - "image": "selenoid/vnc:opera_42.0", - "port": "4444" - }, - "41.0": { - "image": "selenoid/vnc:opera_41.0", - "port": "4444" - }, - "40.0": { - "image": "selenoid/vnc:opera_40.0", - "port": "4444" - }, - "39.0": { - "image": "selenoid/vnc:opera_39.0", - "port": "4444" - }, - "38.0": { - "image": "selenoid/vnc:opera_38.0", - "port": "4444" - }, - "37.0": { - "image": "selenoid/vnc:opera_37.0", - "port": "4444" - }, - "36.0": { - "image": "selenoid/vnc:opera_36.0", - "port": "4444" - }, - "35.0": { - "image": "selenoid/vnc:opera_35.0", - "port": "4444" - }, - "34.0": { - "image": "selenoid/vnc:opera_34.0", - "port": "4444" - }, - "33.0": { - "image": "selenoid/vnc:opera_33.0", - "port": "4444" - }, - "12.1": { - "image": "selenoid/vnc:opera_12.1", - "port": "4444", - "path": "/wd/hub" - } - } - } -} ----- -.Example moon-config/service.json file contents -[source,json] ----- -{ - "images": { - "videoRecorder": "aerokube/moon-video-recorder:devel", - "defender": "aerokube/defender:devel", - "logger": "aerokube/logger:devel" - } -} -----

    -

    .Example moon-openshift.yaml file contents -[source,yaml] ----- -kind: Template -apiVersion: v1 -metadata: - name: moon -objects:

    -

    - kind: ResourceQuota - apiVersion: v1 - metadata: - name: max-moon-sessions - spec: - hard: - pods: ${MOON_PODS}

    -

    - kind: Service - apiVersion: v1 - metadata: - name: moon - spec: - selector: - app: moon - ports: - - name: moon - protocol: TCP - port: 4444 - type: NodePort

    -

    - kind: Service - apiVersion: v1 - metadata: - name: moon-api - spec: - selector: - app: moon-api - ports: - - name: moon-api - protocol: TCP - port: 8080 - type: NodePort

    -

    - kind: Service - apiVersion: v1 - metadata: - name: moon-ui - spec: - selector: - app: moon-ui - ports: - - name: moon-ui - protocol: TCP - port: 8080 - type: NodePort

    -

    - kind: DeploymentConfig - apiVersion: v1 - metadata: - name: moon - spec: - replicas: 1 - template: - metadata: - labels: - app: moon - spec: - containers: - - name: moon - image: ${MOON_IMAGE} - args: - - '-namespace' - - '${NAMESPACE}' - resources: - limits: - cpu: "1" - memory: "512Mi" - requests: - cpu: "0.25" - memory: "64Mi" - ports: - - containerPort: 4444 - volumeMounts: - - name: quota - mountPath: /quota - readOnly: true - - name: users - mountPath: /users - readOnly: true - volumes: - - name: quota - configMap: - name: quota - - name: users - secret: - secretName: users

    -

    - kind: DeploymentConfig - apiVersion: v1 - metadata: - name: moon-api - spec: - replicas: 1 - template: - metadata: - labels: - app: moon-api - spec: - containers: - - name: moon-api - image: ${MOON_API_IMAGE} - args: - - '-namespace' - - '${NAMESPACE}' - resources: - limits: - cpu: "0.25" - memory: "128Mi" - requests: - cpu: "0.1" - memory: "64Mi" - ports: - - containerPort: 8080 - volumeMounts: - - name: quota - mountPath: /quota - volumes: - - name: quota - configMap: - name: quota - - name: users - secret: - secretName: users

    -

    - kind: DeploymentConfig - apiVersion: v1 - metadata: - name: moon-ui - spec: - replicas: 1 - template: - metadata: - labels: - app: moon-ui - spec: - containers: - - name: moon-ui - args: - - '--selenoid-uri' - - 'http://moon-api:8080' - image: ${MOON_UI_IMAGE} - ports: - - containerPort: 8080 - protocol: TCP - resources: - limits: - cpu: 100m - memory: 64M

    -

    parameters: -- name: NAMESPACE - displayName: Namespace - description: Namespace where the Moon is running - value: default - required: true

    -

    - name: MOON_IMAGE - displayName: Moon docker image - description: Name of the image to be used. - value: aerokube/moon:latest-release - required: true

    -

    - name: MOON_API_IMAGE - displayName: Moon-API docker image - description: Name of the image to be used. - value: aerokube/moon-api:latest-release - required: true

    -

    - name: MOON_UI_IMAGE - displayName: Moon-UI docker image - description: Name of the image to be used. - value: aerokube/selenoid-ui:latest-release - required: true

    -

    - name: MOON_PODS - displayName: Max moon pods in project - description: Specify max moon pods for project (4 free slots + Moon + Moon API + Moon UI = 7). - value: '7' - required: true -----

    -cpu-limit

    1

    Hard CPU limit for browser container (no more than this limit is given)

    -cpu-request

    1

    Soft (guaranteed) CPU limit for browser container

    -memory-limit

    1Gi

    Hard memory limit for browser container

    -memory-request

    512Mi

    Soft memory limit for browser container

    +
    +

    You can also override the same values for every browser image in browsers list file:

    +
    +
    +
    Overriding Resources in Browsers List File
    +
    +
    {
    +  "firefox": {
    +    "default": "62.0",
    +    "versions": {
    +      "62.0":
    +        "image": "selenoid/firefox:62.0",
    +        "port": "4444",
    +        "path": "/wd/hub",
    +        "resources": {                              (1)
    +          "limits": {                               (2)
    +            "cpu": "2",                             (3)
    +            "memory": "2Gi"                         (4)
    +          },
    +          "requests": {                             (5)
    +            "cpu": "200m",                          (6)
    +            "memory": "1Gi"                         (7)
    +          }
    +        }
    +      }
    +    }
    +  }
    +}
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    1Resources definition section
    2Limits definition section
    3CPU limit field
    4Memory limit field
    5Requests definition section
    6CPU request field
    7Memory request field
    +
    +
    +
    +

    2.6.5. Running Browser Pods in Privileged Mode

    +
    +

    In some cases like running Android emulators browser container should be run in privileged mode. This setting can be applied separately to each browser version in browsers list file as follows:

    +
    +
    +
    Starting Container in Privileged Mode
    +
    +
    {
    +  "firefox": {
    +    "default": "62.0",
    +    "versions": {
    +      "62.0":
    +        "image": "selenoid/firefox:62.0",
    +        "port": "4444",
    +        "path": "/wd/hub",
    +        "privileged": true                  (1)
    +      }
    +    }
    +  }
    +}
    +
    +
    +
    + + + + + +
    1Launch container in privileged mode
    +
    +
    +
    +

    2.6.6. Using Node Selectors

    +
    +

    Sometimes you may need to run browser pods on particular Kubernetes nodes (i.e. hardware hosts) only. Kubernetes allows to do this by specifying so called node selectors. To provide such selector to Moon browser pods update browsers list as shown below:

    +
    +
    +
    Adding Node Selectors
    +
    +
    {
    +  "firefox": {
    +    "default": "62.0",
    +    "versions": {
    +      "62.0":
    +        "image": "selenoid/firefox:62.0",
    +        "port": "4444",
    +        "path": "/wd/hub",
    +        "nodeSelector": {                    (1)
    +          "node-type": "hardware"
    +        },
    +      }
    +    }
    +  }
    +}
    +
    +
    +
    + + + + + +
    1Node selector for this browser version
    +
    +
    + +
    +

    2.7. Log Files

    +
    +

    Every log line contains:

    +
    + + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table 5. Log entry contents
    FieldExampleNotes

    Time

    2017/11/01 19:12:42

    -

    Status

    [SESSION_ATTEMPTED]

    See table below for complete list of statuses.

    Additional fields

    [firefox-45.0]

    One or more sections showing additional information such as browser name, user name, IP address or error message

    Attempt number

    [1]

    For SESSION_ATTEMPTED or SESSION_CREATED entries means current attempt number. For SESSION_CREATED entries means total number of attempts to create this session.

    Duration

    [4.15s]

    For some log entries this field shows how much time operation took

    +
    +

    The following statuses are available:

    +
    + + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table 6. Log entry statuses
    StatusDescription

    AWAITING_SERVICE

    Waiting for Kubernetes service to start

    BAD_REQUEST

    Failed to process user request

    BAD_RESOURCES

    User incorrectly configured browser container resources

    BAD_SCREEN_RESOLUTION

    User requested to set wrong custom screen resolution

    BAD_TIMEZONE

    User requested to set wrong custom time zone inside container

    BAD_TIMEOUT

    User requested to set wrong session timeout

    BAD_VIDEO_FRAME_RATE

    User requested to capture video with wrong frame rate

    BAD_VIDEO_SCREEN_SIZE

    User requested to capture video with wrong screen size

    CLIENT_DISCONNECTED

    User disconnected and session was interrupted

    CREATING_POD

    Starting to create pod with browser

    CREATING_SERVICE

    Starting to create service for browser session

    DELETING_POD

    Starting to delete pod with browser

    DELETING_SERVICE

    Starting to delete service for browser session

    DELETING_SESSION

    Received request to delete browser session

    EMPTY_REQUEST

    Received empty request from user

    FAILED_TO_CREATE_POD

    Failed to create browser pod

    FAILED_TO_CREATE_SERVICE

    Failed to create browser service

    FAILED_TO_DELETE_POD

    Failed to delete browser pod

    FAILED_TO_DELETE_SERVICE

    Failed to delete browser service

    FAILED_TO_DELETE_SESSION

    Failed to delete browser session

    FAILED_TO_GET_LOGS

    Failed to get session logs

    FORBIDDEN_TO_CREATE_POD

    Kubernetes return forbidden status when creating pod

    INIT

    Service initialization messages

    LOGS

    Requested session logs

    LOGS_CLIENT_DISCONNECTED

    Client disconnected while streaming session logs

    MALFORMED_VOLUME

    Moon skipped malformed volume specification from browsers.json

    POD_CREATED

    Browser pod created

    POD_DELETED

    Browser pod deleted

    PROXYING

    Proxying requests to specified URL

    PROXY_ERROR

    Failed to proxy requests to specified URL

    SERVER_ERROR

    Failed to create pod or service due to internal server error (probably a bug)

    SERVICE_CREATED

    Browser service created

    SERVICE_DELETED

    Browser service deleted

    SERVICE_IS_UP

    Browser service successfully started

    SESSION_CREATED

    Browser session successfully created

    SESSION_DELETED

    Session successfully deleted

    SESSION_FAILED

    Failed to create new session

    SESSION_TIMED_OUT

    Existing session timed out

    SESSION_NOT_FOUND

    Received request with empty session ID

    SHUTTING_DOWN

    Shutting down the service

    STATUS_ERROR

    Failed to refresh Moon status

    STATUS_REQUEST

    Received Moon status request

    STATUS_REQUEST_ERROR

    Failed to return Moon status

    UNSUPPORTED_BROWSER

    User requested unsupported browser

    USER_NOT_FOUND

    Trying to request session with unknown user

    VNC_CLIENT_DISCONNECTED

    User disconnected while proxying VNC traffic

    VNC_ERROR

    An error occurred while proxying VNC traffic

    VNC_SESSION

    User requested VNC session

    VNC_SESSION_CLOSED

    User closed VNC session

    +
    +
    +

    2.8. CLI Flags

    +
    +

    These flags should be specified in Kubernetes YAML files when starting the cluster.

    +
    +
    +

    The following flags are supported by moon:

    +
    +
    +
    +
    -config-file string
    +    optional configuration file (default "config/service.json")
    +-cpu-limit string
    +    browser container cpu limit (default "1")
    +-cpu-request string
    +    browser container cpu request (default "0.5")
    +-credentials-dir string
    +    directory where credentials are mounted (default "credentials")
    +-grace-period duration
    +    graceful shutdown (default 30s)
    +-guest-user string
    +    guest quota user name (default "browsers")
    +-license-file string
    +    path to license file (default "license/license.key")
    +-listen string
    +    address to bind (default ":4444")
    +-memory-limit string
    +    browser container memory limit (default "1Gi")
    +-memory-request string
    +    browser container memory request (default "512Mi")
    +-namespace string
    +    namespace
    +-quota-dir string
    +    quota directory (default "quota")
    +-session-attempt-timeout duration
    +    new session attempt timeout (default 30m0s)
    +-timeout duration
    +    override session timeout (default 1m0s)
    +-users-file string
    +    path to users file (default "users/users.htpasswd")
    +-version
    +    show version and exit
    +
    +
    +
    + + +
    +

    3. Advanced Features

    +
    +
    +

    3.1. Special Capabilities

    +
    +

    Moon supports a set of custom capabilities. You can pass them in tests to enable or disable some features.

    +
    +
    +

    3.1.1. Live Browser Screen: enableVNC

    +
    +

    Moon supports showing browser screen during test execution. To see browser screen add capability:

    +
    +
    +
    Type: boolean
    +
    +
    enableVNC: true
    +
    +
    +
    +

    Browser screen will be shown in Selenoid UI.

    +
    +
    +
    +

    3.1.2. Custom Screen Resolution: screenResolution

    +
    +

    Moon allows you to set custom screen resolution in containers being run:

    +
    +
    +
    Type: string, format: <width>x<height>
    +
    +
    screenResolution: "1280x1024"
    +
    +
    +
    +

    You can optionally add colors depth:

    +
    +
    +
    Type: string, format: <width>x<height>x<colors-depth>
    +
    +
    screenResolution: "1280x1024x24"
    +
    +
    +
    + + + + + +
    + + +
    +

    This capability sets only screen resolution - not browser window size. +Most of browsers have some default window size value this is why your screenshot size can be smaller than screen resolution specified in capability. +You should manually resize window to desired width and height or use Selenium maximize operation.

    +
    +
    +
    +
    +
    +

    3.1.3. Video Recording: enableVideo, videoName, videoScreenSize, videoFrameRate, videoCodec

    +
    +

    To enable video recording for session, add:

    +
    +
    +
    Type: boolean
    +
    +
    enableVideo: true
    +
    +
    +
    +
      +
    • +

      By default saved video files are named <session-id>.mp4 where <session-id> is a unique identifier of Selenium session. +To provide custom video name specify:

      +
      +
      Type: string
      +
      +
      videoName: "my-cool-video.mp4"
      +
      +
      +
      + + + + + +
      + + +It is important to add mp4 file extension. +
      +
      +
    • +
    • +

      By default the entire screen picture is being recorded. +Specifying screenResolution capability changes recorded video size (width and height) accordingly. +You can override video screen size by passing a capability. In case of videoScreenSize +resolution is less than actual, screen on video will be trimmed starting from top-left corner:

      +
      +
      Type: string
      +
      +
      videoScreenSize: "1024x768"
      +
      +
      +
    • +
    • +

      Default video frame rate is 12 frames per second. Specifying videoFrameRate capability changes this value:

      +
      +
      Type: int
      +
      +
      videoFrameRate: 24
      +
      +
      +
    • +
    • +

      By default Moon is using libx264 codec for video output. If this codec is consuming too much CPU, you can change it using videoCodec capability:

      +
      +
      Type: string
      +
      +
      videoCodec: "mpeg4"
      +
      +
      +
    • +
    +
    +
    +
    +

    3.1.4. Custom Test Name: name

    +
    +

    For debugging purposes it is often useful to give a distinct name to every test case. You can set test case name by passing the following capability:

    +
    +
    +
    Type: string
    +
    +
    name: "myCoolTestName"
    +
    +
    +
    +

    The main application of this capability - is debugging tests in the UI which is showing specified name for every running session.

    +
    +
    +
    +

    3.1.5. Per-session Time Zone: timeZone

    +
    +

    Some tests require particular time zone to be set in operating system.

    +
    +
    +
    Type: string
    +
    +
    timeZone: "Europe/Moscow"
    +
    +
    +
    +

    You can find most of available time zones here. +Without this capability launched browser containers will have Moon timezone.

    +
    +
    +
    +

    3.1.6. Per-session Environment Variables: env

    +
    +

    Sometimes you may want to set some environment variables for every test case (for example to test with different default locales). To achieve this pass one more capability:

    +
    +
    +
    Type: array, format: <key>=<value>
    +
    +
    env: ["LANG=ru_RU.UTF-8", "LANGUAGE=ru:en", "LC_ALL=ru_RU.UTF-8"]
    +
    +
    +
    +

    Environment variables from this capability are appended to variables from configuration file.

    +
    +
    +
    +

    3.1.7. Hosts Entries: hostsEntries

    +
    +

    Although you can configure a separate list of /etc/hosts entries for every browser image in Browsers List sometimes you may need to add more entries for particular test cases. This can be easily achieved with:

    +
    +
    +
    Type: array, format: <hostname>:<ip-address>
    +
    +
    hostsEntries: ["example.com:192.168.0.1", "test.com:192.168.0.2"]
    +
    +
    +
    +

    Entries from this capability will be override /etc/hosts entries from browsers list file.

    +
    +
    +
    +

    3.1.8. Custom Session Timeout: sessionTimeout

    +
    +

    Sometimes you may want to change idle timeout for selected browser session. To achieve this - pass the following capability:

    +
    +
    +
    Type: int
    +
    +
    sessionTimeout: 1m30s
    +
    +
    +
    +

    Timeout is always specified in Golang duration format, e.g. 30s or 2m or 1h and so on.

    +
    +
    +
    +

    3.1.9. Specifying Capabilities via Protocol Extensions

    +
    +

    Some Selenium clients allow passing only a limited number of capabilities specified in WebDriver specification. For such cases Moon supports reading capabilities using WebDriver protocol extensions feature. The following two examples deliver the same result. Usually capabilities are passed like this:

    +
    +
    +
    Passing Capabilities as Usually
    +
    +
    {"browserName": "firefox", "version": "62.0", "screenResolution": "1280x1024x24"}
    +
    +
    +
    +

    Moon is using moon:options key to read protocol extension capabilities:

    +
    +
    +
    Passing Capabilities using Protocol Extensions
    +
    +
    {"browserName": "firefox", "version": "62.0", "moon:options": {"screenResolution": "1280x1024x24"}}
    +
    +
    +
    +
    +
    +

    3.2. Accessing Files Downloaded with Browser

    +
    + + + + + +
    + + +Files are accessible only when browser session is running. +
    +
    +
    +

    Your tests may need to download files with browsers. To analyze these files a common requirement is then to somehow extract downloaded files from browser containers. Moon provides a /download API dramatically simplifying downloading such files. To work with it:

    +
    +
    +
      +
    1. +

      Start a new session, for example with ID firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840.

      +
    2. +
    3. +

      In tests code save all files to ~/Downloads directory.

      +
    4. +
    5. +

      Access all downloaded files using an URL:

      +
      +
      +
      http://moon-host.example.com:4444/download/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840/myfile.txt
      +
      +
      +
    6. +
    7. +

      Close the session

      +
    8. +
    +
    +
    +
    +

    3.3. Accessing Clipboard

    +
    + + + + + +
    + + +Clipboard is accessible only when browser session is running. +
    +
    +
    +

    Sometimes you may need to interact with the clipboard to check that your application copy-paste feature works. Moon has a dedicated API to interact with the clipboard. To use it:

    +
    +
    +
      +
    1. +

      Start a new session, for example with ID firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840.

      +
    2. +
    3. +

      To get clipboard value send the following HTTP request:

      +
      +
      +
      $ curl http://moon-host.example.com:4444/clipboard/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840
      +
      +some-clipboard-value
      +
      +
      +
    4. +
    5. +

      To update clipboard value:

      +
      +
      +
      $ curl -X POST --data 'some-clipboard-value' http://moon-host.example.com:4444/clipboard/firefox-61-0-f2bcd32b-d932-4cdc-a639-687ab8e4f840
      +
      +
      +
    6. +
    +
    +
    +
    +
    +
    +

    4. License Agreement

    +
    +
    +

    Last updated January 5th, 2018. Replaces the prior version in its entirety.

    +
    +
    +

    This is a legal agreement. By downloading, installing, copying, saving on Customer’s computer, or otherwise using Aerokube software, support or products Customer becomes a party to this Agreement and Customer consents to be bound by all the terms and conditions set forth below.

    +
    +
    +
      +
    1. +

      Parties

      +
      +
        +
      1. +

        "Aerokube", "Licensor" or "We" means Aerokube OÜ, having its principal place of business at Narva mnt 7-123, Tallinn city, Harju county, 10117, Estonia, registered in the Commercial Register of Estonia, registry code: 12345678.

        +
      2. +
      3. +

        "Customer", "Licensee" or "You" means the sole proprietor or legal entity specified in the Subscription Confirmation. For legal entities, "Customer" includes any entity which controls, is controlled by, or is under common control with Customer. For the purposes of this definition, "control" means one of the following:

        +
        +
          +
        1. +

          The power, directly or indirectly, to direct or manage such entity, whether by contract or otherwise.

          +
        2. +
        3. +

          Ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity.

          +
        4. +
        +
        +
      4. +
      +
      +
    2. +
    3. +

      Definitions

      +
      +
        +
      1. +

        "Agreement" means this License Agreement.

        +
      2. +
      3. +

        "Product" means any generally available Licensor’s software product identified by Licensor as a software developer tool. For the avoidance of doubt, the Product is not produced to the specifications of Customer nor customized through modification or personalization, is intended for mass distribution, and no software code will be provided to Customer.

        +
      4. +
      5. +

        "User" means any employee, independent contractor or other personnel obtaining access to the Product(s) from Customer.

        +
      6. +
      7. +

        "Number of Concurrent Sessions" means maximum number of software testing processes being run using the Product in parallel. This can be for example browsers executing User’s tests.

        +
      8. +
      9. +

        "License Key" means a unique key-code that enables a Licensee to use the Product by unlocking the fixed Number of Concurrent Sessions. Only Licensor and/or its representatives are permitted to produce License Keys for the Product.

        +
      10. +
      11. +

        "Subscription" means an arrangement for making use of the Product of periodic nature on a prepayment plan. For the purpose of clarity, Subscription includes the subscription term, Products provided to Customer, subscription fees, payment schedules and fixed number of License Keys.

        +
      12. +
      13. +

        "Product Evaluation" means using the Product without a valid License Key.

        +
      14. +
      15. +

        "Subscription Confirmation" means an email confirming Customer’s rights to access and use Products, including total Number of Concurrent Sessions.

        +
      16. +
      17. +

        "Product Installation" means a Product copy running on Customer’s computer device, hardware server or virtual machine.

        +
      18. +
      19. +

        "Product Version" means a release, update, or upgrade of a particular Product that is not identified by Licensor as being made for the purpose of fixing software bugs.

        +
      20. +
      21. +

        "Bug Fix Update" for a particular Product Version means a software update or release that is specifically identified by Licensor as a bug fix for that Product Version.

        +
      22. +
      23. +

        "Fallback Date" means the date that was 12 months prior to the date of expiration of the Subscription.

        +
      24. +
      25. +

        "Fallback Version" means the most recent Product Version that Licensor made available for public purchase prior to the Fallback Date, along with any Bug Fix Updates for that Product Version. For the purpose of clarity, Fallback Version does not include any Product updates or upgrades other than Bug Fix Updates that Customer may have used in the period between the Fallback Date and the date of expiration of the Subscription.

        +
      26. +
      27. +

        "E-mail Support" means a form of customer support provided by the Licensor. At the time of writing, the corresponding e-mail address is support@aerokube.com; should the address be changed, the new address will be referred to on the Licensor’s web site.

        +
      28. +
      29. +

        "Instant Messaging Support" means a form of customer support provided by the Licensor. At the time of writing, the corresponding address to support channel is https://t.me/aerokube_moon; should the address be changed, the new address will be referred to on the Licensor’s web site.

        +
      30. +
      31. +

        "Affiliate" means any entity belonging to the same group as the Licensor.

        +
      32. +
      +
      +
    4. +
    5. +

      How this Agreement Works

      +
      +
        +
      1. +

        Entire Agreement. This Agreement, including the Third-Party Software license terms, constitutes the entire agreement between the parties concerning its subject matter and supersedes any prior agreements between Customer and Licensor regarding Customer’s use of any Products. No purchase order, other ordering document or any handwritten or typewritten text which purports to modify or supplement the printed text of this Agreement or any schedule will add to or vary the terms of this Agreement unless signed by both Customer and Licensor.

        +
      2. +
      3. +

        Reservation of Rights. Aerokube reserves the right at any time to cease the support of the Product and to alter prices, features, specifications, capabilities, functions, terms of use, release dates, general availability or other characteristics of the Product.

        +
      4. +
      5. +

        Changes to this Agreement. We may update or modify this Agreement from time to time, including any referenced policies and other documents. If a revision meaningfully reduces Customer’s rights, we will use reasonable efforts to notify Customer. If we modify this Agreement, the modified version of the Agreement will be effective from the start of the next Subscription term. In this case, if Customer objects to the updated Agreement terms, as Customer’s exclusive remedy, Customer may cancel the Subscription. Customer may be required to click through the updated Agreement to show its acceptance. For the avoidance of doubt, each Subscription Confirmation is subject to the version of the Agreement in effect on the Subscription Confirmation date.

        +
      6. +
      7. +

        Opportunity to Review. Customer hereby declares that Customer has had sufficient opportunity to review this Agreement, understand the content of all of its clauses, negotiate its terms, and seek independent professional legal advice in that respect before entering into it. Consequently, any statutory "form contract" ("adhesion contract") regulations shall not be applicable to this Agreement.

        +
      8. +
      9. +

        Severability. If a particular term of this Agreement is not enforceable, the unenforceability of that term will not affect any other terms of this Agreement.

        +
      10. +
      11. +

        Headings. Headings and titles are for convenience only and do not affect the interpretation of this Agreement.

        +
      12. +
      13. +

        No Waiver. Our failure to enforce or exercise any part of this Agreement is not a waiver of that section.

        +
      14. +
      15. +

        Notice. Aerokube may deliver any notice to Customer via electronic mail to an email address provided by Customer, registered mail, personal delivery or renowned express courier (such as DHL, FedEx or UPS). Any such notice will be deemed to be effective:

        +
        +
          +
        1. +

          On the day the notice is sent to Customer via email.

          +
        2. +
        3. +

          Upon personal delivery.

          +
        4. +
        5. +

          One (1) day after deposit with an express courier or five (5) days after deposit in the mail, whichever occurs first.

          +
        6. +
        +
        +
      16. +
      17. +

        Governing Law. This Agreement will be governed by the laws of the Estonia, without reference to conflict of laws principles. Customer agrees that any litigation relating to this Agreement may only be brought in, and will be subject to the jurisdiction of, any competent court of the Estonia. The parties agree that the United Nations Convention on Contracts for the International Sale of Goods does not apply to this Agreement.

        +
      18. +
      19. +

        Exceptions or Modifications. For exceptions or modifications to this Agreement, please contact Aerokube at: support@aerokube.com In case the terms of this Agreement are in conflict with the terms of any agreement individually negotiated and agreed between Aerokube and Customer, the terms of the latter shall prevail.

        +
      20. +
      21. +

        Force Majeure. Except with respect to Customer’s payment obligations, neither party shall be liable to the other for any delay or failure to perform any obligation under this Agreement (except for a failure to pay fees) if the delay or failure is due to unforeseen events which occur after the signing of this Agreement and which are beyond the reasonable control of such party ("Force Majeure Event"), such as a strike, blockade, war, act of terrorism, riot, natural disaster, failure or diminishment of power or telecommunications or data networks or services, or refusal of a license by a government agency. In the event of a Force Majeure Event that prevents one part from substantially performing its obligations hereunder for a period of ten (10) days or more, either party may terminate this Agreement on five (5) days written notice.

        +
      22. +
      +
      +
    6. +
    7. +

      Grant of Rights

      +
      +
        +
      1. +

        The Product include code and libraries licensed to Licensor by third parties, including open source software.

        +
      2. +
      3. +

        The Product is provided basing on the Number of Concurrent Sessions. If Customer complies with the terms of this Agreement, Customer has the rights stipulated hereunder for each Subscription that Customer acquires. Customer’s rights acquired in relation to the Product are limited to those necessary to enable Customer and its Users to effectively operate the Product(s). All other rights remain reserved to Licensor.

        +
      4. +
      5. +

        Unless the Subscription has expired or this Agreement is terminated in accordance with respective section, and subject to the terms and conditions specified herein, Licensor grants Customer a non-exclusive and non-transferable right to use each Product covered by the Subscription as stipulated below.

        +
      6. +
      7. +

        Customer may:

        +
        +
          +
        1. +

          For each License Key included to Subscription have one Product Installation of any version covered by the Subscription on any operating system supported by the Product.

          +
        2. +
        3. +

          Make one backup copy of the Product solely for archival/security backup purposes.

          +
        4. +
        +
        +
      8. +
      9. +

        Customer may not:

        +
        +
          +
        1. +

          Allow the same Product Installation to be used concurrently by more than the Number of Concurrent Sessions specified for used License Key in Subscription Confirmation.

          +
        2. +
        3. +

          Rent, lease, reproduce, modify, adapt, create derivative works of, distribute, sell, or transfer the Product.

          +
        4. +
        5. +

          Provide access to the Product or the right to use the Product to a third party.

          +
        6. +
        7. +

          Reverse engineer, decompile, disassemble, modify, translate, make any attempt to discover the source code of the Product.

          +
        8. +
        9. +

          Remove or obscure any proprietary or other notices contained in the Product.

          +
        10. +
        +
        +
      10. +
      11. +

        Following the expiration of this Agreement, the rights stipulated in "Grant of Rights" section shall continue on a perpetual, royalty-free, non-exclusive, and non-transferable basis for the continued use of a Fallback Version of each Product covered by the Subscription. The limitations set forth in this section apply to the usage of the Fallback Version. The rights granted in this section are expressly contingent upon Customer not being in breach of this Agreement, including having paid in full the applicable Subscription fees for the preceding 12 months or longer without interruption.

        +
      12. +
      13. +

        Customer acknowledges that no ownership right is conveyed to Customer under this Agreement, irrespective of the use of terms such as "purchase" or "sale". Licensor has and retains all rights, title and interest, including all intellectual property rights, in and to the Products and any and all related or underlying technology, and any modifications or derivative works thereof, including without limitation as they may incorporate Feedback (as defined below).

        +
      14. +
      15. +

        This Agreement applies whether Customer purchases a Subscription directly from Licensor or through resellers. If Customer purchases through a reseller, the Subscription details shall be as stated in the Subscription Confirmation issued by the reseller to Customer, and the reseller is responsible for the accuracy of any such Subscription Confirmation. Resellers are not authorized to make any promises or commitments on Licensor behalf, and Customer understands and agrees that Licensor is not bound by any obligations to Customer other than as specified in this Agreement.

        +
      16. +
      +
      +
    8. +
    9. +

      Access to Products

      +
      +
        +
      1. +

        All deliveries under this Agreement will be electronic. Customer and its Users must have an Internet connection in order to receive any deliveries. For the avoidance of doubt, Customer is responsible for downloading and installing the Products. Download instructions are made available on Licensor website at http://aerokube.com.

        +
      2. +
      3. +

        Customer enables full access to Product Installation by specifying a License Key from Subscription Confirmation.

        +
      4. +
      5. +

        Subject to the terms of this Agreement, Customer is granted a right to install and use the Product for evaluation purposes without charge for unlimited amount of time. The Product contains a feature that will automatically limit allowed Number of Concurrent Sessions. Licensor reserves the right at any time to change that limit in new Product versions.

        +
      6. +
      +
      +
    10. +
    11. +

      Fees

      +
      +
        +
      1. +

        Customer shall pay its Subscription fees in accordance with Licensor Terms of Purchase or the reseller’s terms of purchase, whichever are applicable.

        +
      2. +
      3. +

        The Subscription fees shall be paid in full, and any levies, duties and/or taxes imposed by Customer’s jurisdiction (including, but not limited to, value added tax, sales tax and withholding tax), shall be borne solely by Customer.

        +
      4. +
      5. +

        Customer may not deduct any amounts from fees payable to Licensor or the reseller, unless otherwise specified in the applicable terms of purchase.

        +
      6. +
      +
      +
    12. +
    13. +

      Feedback

      +
      +
        +
      1. +

        Customer has no obligation to provide Licensor with ideas, suggestions, or proposals ("Feedback").

        +
      2. +
      3. +

        If Customer or Users submit Feedback to Licensor, then Customer grants Licensor a non-exclusive, worldwide, royalty-free license that is sub-licensable and transferable, to make, use, sell, have made, offer to sell, import, reproduce, publicly display, distribute, modify, or publicly perform the Feedback in any manner without any obligation, royalty or restriction based on intellectual property rights or otherwise.

        +
      4. +
      +
      +
    14. +
    15. +

      LIMITED WARRANTY

      +
      +

      ALL PRODUCTS ARE PROVIDED TO CUSTOMER ON AN "AS IS" AND "AS AVAILABLE" BASIS WITHOUT WARRANTIES. USE OF THE PRODUCTS IS AT YOUR OWN RISK. AEROKUBE MAKES NO WARRANTY AS TO THEIR USE OR PERFORMANCE. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, AEROKUBE, AND ITS SUPPLIERS (WHICH SHALL INCLUDE THE PROVIDERS OF THE THIRD PARTY SOFTWARE) AND RESELLERS, DISCLAIM ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, WITH REGARD TO THE PRODUCTS, AND THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES. THIS LIMITED WARRANTY GIVES CUSTOMER SPECIFIC LEGAL RIGHTS. CUSTOMER MAY HAVE OTHER RIGHTS, WHICH VARY FROM STATE/JURISDICTION TO STATE/JURISDICTION. AEROKUBE (AND ITS AFFILIATES, AGENTS, DIRECTORS AND EMPLOYEES) DOES NOT WARRANT:

      +
      +
      +
        +
      1. +

        THAT THE PRODUCTS ARE ACCURATE, RELIABLE OR CORRECT

        +
      2. +
      3. +

        THAT THE PRODUCTS WILL MEET YOUR REQUIREMENTS

        +
      4. +
      5. +

        THAT THE PRODUCTS WILL BE AVAILABLE AT ANY PARTICULAR TIME OR LOCATION, UNINTERRUPTED OR SECURE

        +
      6. +
      7. +

        THAT ANY DEFECTS OR ERRORS WILL BE CORRECTED

        +
      8. +
      9. +

        THAT THE PRODUCTS ARE FREE OF VIRUSES OR OTHER HARMFUL COMPONENTS

        +
      10. +
      +
      +
      +

      ANY CONTENT OR DATA DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE PRODUCTS ARE DOWNLOADED AT YOUR OWN RISK AND YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR PROPERTY OR LOSS OF DATA THAT RESULTS FROM SUCH DOWNLOAD. NO WARRANTY OR LIABILITY AT ALL IS GIVEN TO PRODUCTS UNDER EVALUATION.

      +
      +
    16. +
    17. +

      DISCLAIMER OF DAMAGES

      +
      +
        +
      1. +

        TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL AEROKUBE (OR ITS AFFILIATES, AGENTS, DIRECTORS, OR EMPLOYEES), OR AEROKUBE LICENSORS, SUPPLIERS OR RESELLERS BE LIABLE TO CUSTOMER OR ANYONE ELSE FOR:

        +
        +
          +
        1. +

          ANY LOSS OF USE, DATA, GOODWILL, OR PROFITS, WHETHER OR NOT FORESEEABLE

          +
        2. +
        3. +

          ANY LOSS OR DAMAGES IN CONNECTION WITH TERMINATION OR SUSPENSION OF CUSTOMER’S ACCESS TO OUR PRODUCTS IN ACCORDANCE WITH THIS AGREEMENT

          +
        4. +
        5. +

          ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, EXEMPLARY OR PUNITIVE DAMAGES WHATSOEVER (EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF THESE DAMAGES), INCLUDING THOSE:

          +
          +
            +
          1. +

            RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER OR NOT FORESEEABLE

            +
          2. +
          3. +

            BASED ON ANY THEORY OF LIABILITY, INCLUDING BREACH OF CONTRACT OR WARRANTY, STRICT LIABILITY, NEGLIGENCE OR OTHER TORTIOUS ACTION

            +
          4. +
          5. +

            ARISING FROM ANY OTHER CLAIM ARISING OUT OF OR IN CONNECTION WITH CUSTOMER’S USE OF OR ACCESS TO THE PRODUCTS OR SUPPORT.

            +
          6. +
          +
          +
        6. +
        +
        +
      2. +
      3. +

        THE FOREGOING LIMITATION OF LIABILITY SHALL APPLY TO THE FULLEST EXTENT PERMITTED BY LAW IN THE APPLICABLE JURISDICTION.

        +
      4. +
      5. +

        OUR TOTAL LIABILITY IN ANY MATTER ARISING OUT OF OR IN RELATION TO THIS AGREEMENT IS LIMITED TO ONE HUNDRED (100) US DOLLARS OR THE AGGREGATE AMOUNT PAID OR PAYABLE BY THE CUSTOMER FOR PRODUCTS DURING THE THREE-MONTH PERIOD PRECEDING THE EVENT GIVING RISE TO THE LIABILITY, WHICHEVER IS GREATER. THIS LIMITATION WILL APPLY EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF LIABILITY EXCEEDING SUCH AMOUNT AND NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.

        +
      6. +
      +
      +
    18. +
    19. +

      Term and Termination

      +
      +
        +
      1. +

        The term of this Agreement will commence upon acceptance of this Agreement by Customer as set forth in the preamble above, and will continue for each Product through the end of the applicable subscription period specified in the respective Subscription Confirmation. This Agreement will automatically renew with respect to each Product for a successive subscription term, unless terminated as set forth herein.

        +
      2. +
      3. +

        Customer may terminate this Agreement at any time by cancelling its Product subscription. If such termination occurs during a then-current subscription period, this Agreement will continue to be effective until the end of that subscription period. Such termination does not relieve Customer of the obligation to pay any outstanding subscription fees owed to Licensor, and no credits or refunds will be issued to Customer for prepaid subscription fees (except as specified in the Licensor Terms of Purchase, if applicable).

        +
      4. +
      5. +

        Licensor may terminate this agreement if:

        +
        +
          +
        1. +

          Customer has materially breached this Agreement and fails to cure such breach within thirty (30) days of written notice thereof.

          +
        2. +
        3. +

          Customer fails to make the timely payment of subscription fees in accordance with "Fees" Section of this Agreement.

          +
        4. +
        5. +

          Licensor is required to do so by law (for example, where the provision of the Product to Customer is, or becomes, unlawful).

          +
        6. +
        7. +

          Licensor elects to discontinue providing the Product, in whole or in part.

          +
        8. +
        +
        +
      6. +
      7. +

        Licensor will make reasonable efforts to notify Customer via email as follows:

        +
        +
          +
        1. +

          Thirty (30) days prior to termination of the Agreement when required to terminate by law or because of discontinued Product. In such events Customer will be entitled to a refund of the unused portion of prepaid subscription fees, if applicable.

          +
        2. +
        3. +

          Three (3) days prior to termination of the Agreement in other cases. In such events Customer will not be entitled to any refund of the unused portion of prepaid subscription fees.

          +
        4. +
        +
        +
      8. +
      9. +

        Survival. Upon the expiration or termination of this Agreement by Customer and if Customer elects to use the Fallback Version of the Product this Agreement statements will also survive with respect to said Fallback Version.

        +
      10. +
      +
      +
    20. +
    21. +

      Temporary Suspension for Non-payment

      +
    22. +
    23. +

      Licensor reserves the right to suspend or limit Customer’s access to Aerokube Products if Customer fails to pay subscription fees on time.

      +
    24. +
    25. +

      If Licensor suspends or limits Customer’s access to Aerokube Products for non-payment according, Customer must pay all past due amounts in order to restore full access to Aerokube Products.

      +
    26. +
    27. +

      Customer hereby agrees that Licensor is entitled to charge Customer for the time period during which Customer has access to Aerokube Products until Customer or Licensor terminates or suspends Customer’s subscription in accordance with this Agreement.

      +
    28. +
    29. +

      Export Regulations

      +
      +

      Customer shall comply with all applicable laws and regulations with regards to economic sanctions, export controls, import regulations, and trade embargoes (all herein referred to as "Sanctions"), including those of the European Union and United States (specifically the Export Administration Regulations (EAR)). Customer declares that it is not a person targeted by Sanctions nor is it otherwise owned or controlled by or acting on behalf of any person targeted by Sanctions. Further, Customer warrants that it will not download or otherwise export or re-export the Product or any related technical data directly or indirectly to any person targeted by Sanctions or download or otherwise use the Product for any end-use prohibited or restricted by Sanctions.

      +
      +
    30. +
    31. +

      Customer Support

      +
      +
        +
      1. +

        Licensor provides Email Support as well as Instant Messaging Support. The response time will be reasonable, but no specific response time guarantees are given.

        +
      2. +
      3. +

        Customer may request additional paid support from Licensor which is subject of a supplementary individually negotiated Agreement between Customer and Licensor.

        +
      4. +
      5. +

        Any guarantees of support availability only apply to the latest version of Licensed Software available in Customer Subscription.

        +
      6. +
      +
      +
    32. +
    33. +

      Customer Data

      +
      +
        +
      1. +

        Use of Name and Logo. Customer agrees that Licensor may identify it as a customer of Aerokube and may refer to it by name, trade name and trademark, if applicable. Licensor may also briefly describe Customer’s business in Licensor marketing materials, on the Aerokube website and/or in public or legal documents. Customer hereby grants Licensor a worldwide, non-exclusive and royalty-free license to use Customer’s name and any of Customer’s trade names and trademarks solely pursuant to this marketing section.

        +
      2. +
      3. +

        Gathering of Usage Statistics. Customer acknowledges and agrees that the Product may contain a feature that reports the usage statistics, diagnostics information and usage meta-information of the Product back to the Licensor. Customer may opt out of the gathering of usage statistics by turning off this feature in the Product settings.

        +
      4. +
      +
      +
    34. +
    +
    +
    +
    +
    +

    Appendix A: Pricing

    +
    +
    +
      +
    1. +

      Moon price is calculated using so-called Number of Concurrent Sessions that is to say total number of browser sessions being run in parallel. We control this by limiting total number of simultaneously running browser pods to the value you are purchasing.

      +
    2. +
    3. +

      When no license key is provided 4 (four) parallel browser sessions maximum are allowed. If such limit is sufficient for you - you are allowed use Moon without license key for unlimited period of time.

      +
    4. +
    5. +

      If free limit is insufficient - you need a paid license. Such license can include any desired number of parallel browser sessions (yes, even 42).

      +
    6. +
    7. +

      Every parallel session has a fixed cost - $5 USD (five United States dollars).

      +
      +
      An example price calculation
      +
      +
      42 sessions * $5/month = $210/month
      +
      +
      +
    8. +
    9. +

      For simplicity we calculated monthly prices for some frequent cases:

      +
    10. +
    +
    + + ++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table 7. Moon License Pricing
    Number of Parallel SessionsPrice per Month, USD

    0-4

    free

    5

    $25

    10

    $50

    15

    $75

    20

    $100

    25

    $125

    30

    $150

    40

    $200

    50

    $250

    75

    $375

    100

    $500

    150

    $750

    200

    $1000

    250

    $1250

    500

    $2500

    750

    $2750

    1000

    $5000

    +
    +
    +
    +

    Appendix B: Example Configuration Files

    +
    +
    +
    Example moon-sessions.yaml file contents
    +
    +
    apiVersion: v1
    +kind: ResourceQuota
    +metadata:
    +  name: max-moon-sessions
    +spec:
    +  hard:
    +    pods: "6"
    +---
    +apiVersion: rbac.authorization.k8s.io/v1beta1
    +kind: ClusterRoleBinding
    +metadata:
    +  name: moon-rbac
    +subjects:
    +  - kind: ServiceAccount
    +    name: default
    +    namespace: default
    +roleRef:
    +  kind: ClusterRole
    +  name: cluster-admin
    +  apiGroup: rbac.authorization.k8s.io
    +
    +
    +
    +
    Example moon.yaml file contents
    +
    +
    kind: Service
    +apiVersion: v1
    +metadata:
    +  name: moon
    +spec:
    +  selector:
    +    app: moon
    +  ports:
    +  - protocol: TCP
    +    port: 4444
    +  type: NodePort
    +---
    +apiVersion: apps/v1beta1
    +kind: Deployment
    +metadata:
    +  name: moon
    +spec:
    +  replicas: 1
    +  template:
    +    metadata:
    +      labels:
    +        app: moon
    +    spec:
    +      containers:
    +      - name: moon
    +        image: aerokube/moon:1.3.2
    +        resources:
    +          limits:
    +            cpu: "1"
    +            memory: "512Mi"
    +          requests:
    +            cpu: "0.25"
    +            memory: "64Mi"
    +        ports:
    +        - containerPort: 4444
    +        volumeMounts:
    +        - name: quota
    +          mountPath: /quota
    +          readOnly: true
    +        - name: users
    +          mountPath: /users
    +          readOnly: true
    +      volumes:
    +      - name: quota
    +        configMap:
    +          name: quota
    +      - name: users
    +        secret:
    +          secretName: users
    +
    +
    +
    +
    Example moon-api.yaml file contents
    +
    +
    kind: Service
    +apiVersion: v1
    +metadata:
    +  name: moon-api
    +spec:
    +  selector:
    +    app: moon-api
    +  ports:
    +  - protocol: TCP
    +    port: 8080
    +  type: NodePort
    +---
    +apiVersion: apps/v1beta1
    +kind: Deployment
    +metadata:
    +  name: moon-api
    +spec:
    +  replicas: 1
    +  template:
    +    metadata:
    +      labels:
    +        app: moon-api
    +    spec:
    +      containers:
    +      - name: moon-api
    +        image: aerokube/moon-api:1.3.2
    +        resources:
    +          limits:
    +            cpu: "0.25"
    +            memory: "128Mi"
    +          requests:
    +            cpu: "0.1"
    +            memory: "64Mi"
    +        ports:
    +        - containerPort: 8080
    +        volumeMounts:
    +        - name: quota
    +          mountPath: /quota
    +      volumes:
    +      - name: quota
    +        configMap:
    +          name: quota
    +      - name: users
    +        secret:
    +          secretName: users
    +
    +
    +
    +
    Example browsers.json file contents
    +
    +
    {
    +  "firefox": {
    +    "default": "58.0",
    +    "versions": {
    +      "58.0": {
    +        "image": "selenoid/vnc:firefox_58.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "57.0": {
    +        "image": "selenoid/vnc:firefox_57.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "56.0": {
    +        "image": "selenoid/vnc:firefox_56.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "55.0": {
    +        "image": "selenoid/vnc:firefox_55.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "54.0": {
    +        "image": "selenoid/vnc:firefox_54.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "53.0": {
    +        "image": "selenoid/vnc:firefox_53.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "52.0": {
    +        "image": "selenoid/vnc:firefox_52.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "51.0": {
    +        "image": "selenoid/vnc:firefox_51.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "50.0": {
    +        "image": "selenoid/vnc:firefox_50.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "49.0": {
    +        "image": "selenoid/vnc:firefox_49.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "48.0": {
    +        "image": "selenoid/vnc:firefox_48.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "47.0": {
    +        "image": "selenoid/vnc:firefox_47.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "46.0": {
    +        "image": "selenoid/vnc:firefox_46.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "45.0": {
    +        "image": "selenoid/vnc:firefox_45.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "44.0": {
    +        "image": "selenoid/vnc:firefox_44.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "43.0": {
    +        "image": "selenoid/vnc:firefox_43.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "42.0": {
    +        "image": "selenoid/vnc:firefox_42.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "41.0": {
    +        "image": "selenoid/vnc:firefox_41.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "40.0": {
    +        "image": "selenoid/vnc:firefox_40.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "39.0": {
    +        "image": "selenoid/vnc:firefox_39.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "38.0": {
    +        "image": "selenoid/vnc:firefox_38.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "37.0": {
    +        "image": "selenoid/vnc:firefox_37.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "36.0": {
    +        "image": "selenoid/vnc:firefox_36.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "35.0": {
    +        "image": "selenoid/vnc:firefox_35.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "34.0": {
    +        "image": "selenoid/vnc:firefox_34.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "33.0": {
    +        "image": "selenoid/vnc:firefox_33.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "32.0": {
    +        "image": "selenoid/vnc:firefox_32.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "31.0": {
    +        "image": "selenoid/vnc:firefox_31.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "30.0": {
    +        "image": "selenoid/vnc:firefox_30.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "29.0": {
    +        "image": "selenoid/vnc:firefox_29.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "28.0": {
    +        "image": "selenoid/vnc:firefox_28.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "27.0": {
    +        "image": "selenoid/vnc:firefox_27.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "26.0": {
    +        "image": "selenoid/vnc:firefox_26.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "25.0": {
    +        "image": "selenoid/vnc:firefox_25.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "24.0": {
    +        "image": "selenoid/vnc:firefox_24.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "23.0": {
    +        "image": "selenoid/vnc:firefox_23.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "22.0": {
    +        "image": "selenoid/vnc:firefox_22.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "21.0": {
    +        "image": "selenoid/vnc:firefox_21.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "20.0": {
    +        "image": "selenoid/vnc:firefox_20.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "19.0": {
    +        "image": "selenoid/vnc:firefox_19.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "18.0": {
    +        "image": "selenoid/vnc:firefox_18.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "17.0": {
    +        "image": "selenoid/vnc:firefox_17.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "16.0": {
    +        "image": "selenoid/vnc:firefox_16.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "15.0": {
    +        "image": "selenoid/vnc:firefox_15.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "14.0": {
    +        "image": "selenoid/vnc:firefox_14.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "13.0": {
    +        "image": "selenoid/vnc:firefox_13.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "12.0": {
    +        "image": "selenoid/vnc:firefox_12.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "11.0": {
    +        "image": "selenoid/vnc:firefox_11.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "10.0": {
    +        "image": "selenoid/vnc:firefox_10.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "9.0": {
    +        "image": "selenoid/vnc:firefox_9.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "8.0": {
    +        "image": "selenoid/vnc:firefox_8.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "7.0": {
    +        "image": "selenoid/vnc:firefox_7.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "6.0": {
    +        "image": "selenoid/vnc:firefox_6.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "5.0": {
    +        "image": "selenoid/vnc:firefox_5.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "4.0": {
    +        "image": "selenoid/vnc:firefox_4.0",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      },
    +      "3.6": {
    +        "image": "selenoid/vnc:firefox_3.6",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      }
    +    }
    +  },
    +  "chrome": {
    +    "default": "65.0",
    +    "versions": {
    +      "65.0": {
    +        "image": "selenoid/vnc:chrome_65.0",
    +        "port": "4444"
    +      },
    +      "64.0": {
    +        "image": "selenoid/vnc:chrome_64.0",
    +        "port": "4444"
    +      },
    +      "63.0": {
    +        "image": "selenoid/vnc:chrome_63.0",
    +        "port": "4444"
    +      },
    +      "62.0": {
    +        "image": "selenoid/vnc:chrome_62.0",
    +        "port": "4444"
    +      },
    +      "61.0": {
    +        "image": "selenoid/vnc:chrome_61.0",
    +        "port": "4444"
    +      },
    +      "60.0": {
    +        "image": "selenoid/vnc:chrome_60.0",
    +        "port": "4444"
    +      },
    +      "59.0": {
    +        "image": "selenoid/vnc:chrome_59.0",
    +        "port": "4444"
    +      },
    +      "58.0": {
    +        "image": "selenoid/vnc:chrome_58.0",
    +        "port": "4444"
    +      },
    +      "57.0": {
    +        "image": "selenoid/vnc:chrome_57.0",
    +        "port": "4444"
    +      },
    +      "56.0": {
    +        "image": "selenoid/vnc:chrome_56.0",
    +        "port": "4444"
    +      },
    +      "55.0": {
    +        "image": "selenoid/vnc:chrome_55.0",
    +        "port": "4444"
    +      },
    +      "54.0": {
    +        "image": "selenoid/vnc:chrome_54.0",
    +        "port": "4444"
    +      },
    +      "53.0": {
    +        "image": "selenoid/vnc:chrome_53.0",
    +        "port": "4444"
    +      },
    +      "52.0": {
    +        "image": "selenoid/vnc:chrome_52.0",
    +        "port": "4444"
    +      },
    +      "51.0": {
    +        "image": "selenoid/vnc:chrome_51.0",
    +        "port": "4444"
    +      },
    +      "50.0": {
    +        "image": "selenoid/vnc:chrome_50.0",
    +        "port": "4444"
    +      },
    +      "49.0": {
    +        "image": "selenoid/vnc:chrome_49.0",
    +        "port": "4444"
    +      },
    +      "48.0": {
    +        "image": "selenoid/vnc:chrome_48.0",
    +        "port": "4444"
    +      }
    +    }
    +  },
    +  "opera": {
    +    "default": "50.0",
    +    "versions": {
    +      "50.0": {
    +        "image": "selenoid/vnc:opera_50.0",
    +        "port": "4444"
    +      },
    +      "49.0": {
    +        "image": "selenoid/vnc:opera_49.0",
    +        "port": "4444"
    +      },
    +      "48.0": {
    +        "image": "selenoid/vnc:opera_48.0",
    +        "port": "4444"
    +      },
    +      "47.0": {
    +        "image": "selenoid/vnc:opera_47.0",
    +        "port": "4444"
    +      },
    +      "46.0": {
    +        "image": "selenoid/vnc:opera_46.0",
    +        "port": "4444"
    +      },
    +      "45.0": {
    +        "image": "selenoid/vnc:opera_45.0",
    +        "port": "4444"
    +      },
    +      "44.0": {
    +        "image": "selenoid/vnc:opera_44.0",
    +        "port": "4444"
    +      },
    +      "43.0": {
    +        "image": "selenoid/vnc:opera_43.0",
    +        "port": "4444"
    +      },
    +      "42.0": {
    +        "image": "selenoid/vnc:opera_42.0",
    +        "port": "4444"
    +      },
    +      "41.0": {
    +        "image": "selenoid/vnc:opera_41.0",
    +        "port": "4444"
    +      },
    +      "40.0": {
    +        "image": "selenoid/vnc:opera_40.0",
    +        "port": "4444"
    +      },
    +      "39.0": {
    +        "image": "selenoid/vnc:opera_39.0",
    +        "port": "4444"
    +      },
    +      "38.0": {
    +        "image": "selenoid/vnc:opera_38.0",
    +        "port": "4444"
    +      },
    +      "37.0": {
    +        "image": "selenoid/vnc:opera_37.0",
    +        "port": "4444"
    +      },
    +      "36.0": {
    +        "image": "selenoid/vnc:opera_36.0",
    +        "port": "4444"
    +      },
    +      "35.0": {
    +        "image": "selenoid/vnc:opera_35.0",
    +        "port": "4444"
    +      },
    +      "34.0": {
    +        "image": "selenoid/vnc:opera_34.0",
    +        "port": "4444"
    +      },
    +      "33.0": {
    +        "image": "selenoid/vnc:opera_33.0",
    +        "port": "4444"
    +      },
    +      "12.1": {
    +        "image": "selenoid/vnc:opera_12.1",
    +        "port": "4444",
    +        "path": "/wd/hub"
    +      }
    +    }
    +  }
    +}
    +
    +
    +
    +
    Example moon-config/service.json file contents
    +
    +
    {
    +  "images": {
    +    "videoRecorder": "aerokube/moon-video-recorder:devel",
    +    "defender": "aerokube/defender:devel",
    +    "logger": "aerokube/logger:devel"
    +  }
    +}
    +
    +
    +
    +
    Example moon-openshift.yaml file contents
    +
    +
    kind: Template
    +apiVersion: v1
    +metadata:
    +  name: moon
    +objects:
    +
    +  - kind: ResourceQuota
    +    apiVersion: v1
    +    metadata:
    +      name: max-moon-sessions
    +    spec:
    +      hard:
    +        pods: ${MOON_PODS}
    +
    +  - kind: Service
    +    apiVersion: v1
    +    metadata:
    +      name: moon
    +    spec:
    +      selector:
    +        app: moon
    +      ports:
    +      - name: moon
    +        protocol: TCP
    +        port: 4444
    +      type: NodePort
    +
    +  - kind: Service
    +    apiVersion: v1
    +    metadata:
    +      name: moon-api
    +    spec:
    +      selector:
    +        app: moon-api
    +      ports:
    +      - name: moon-api
    +        protocol: TCP
    +        port: 8080
    +      type: NodePort
    +
    +  - kind: Service
    +    apiVersion: v1
    +    metadata:
    +      name: moon-ui
    +    spec:
    +      selector:
    +        app: moon-ui
    +      ports:
    +      - name: moon-ui
    +        protocol: TCP
    +        port: 8080
    +      type: NodePort
    +
    +  - kind: DeploymentConfig
    +    apiVersion: v1
    +    metadata:
    +      name: moon
    +    spec:
    +      replicas: 1
    +      template:
    +        metadata:
    +          labels:
    +            app: moon
    +        spec:
    +          containers:
    +          - name: moon
    +            image: ${MOON_IMAGE}
    +            args:
    +              - '-namespace'
    +              - '${NAMESPACE}'
    +            resources:
    +              limits:
    +                cpu: "1"
    +                memory: "512Mi"
    +              requests:
    +                cpu: "0.25"
    +                memory: "64Mi"
    +            ports:
    +            - containerPort: 4444
    +            volumeMounts:
    +            - name: quota
    +              mountPath: /quota
    +              readOnly: true
    +            - name: users
    +              mountPath: /users
    +              readOnly: true
    +          volumes:
    +          - name: quota
    +            configMap:
    +              name: quota
    +          - name: users
    +            secret:
    +              secretName: users
    +
    +  - kind: DeploymentConfig
    +    apiVersion: v1
    +    metadata:
    +      name: moon-api
    +    spec:
    +      replicas: 1
    +      template:
    +        metadata:
    +          labels:
    +            app: moon-api
    +        spec:
    +          containers:
    +          - name: moon-api
    +            image: ${MOON_API_IMAGE}
    +            args:
    +              - '-namespace'
    +              - '${NAMESPACE}'
    +            resources:
    +              limits:
    +                cpu: "0.25"
    +                memory: "128Mi"
    +              requests:
    +                cpu: "0.1"
    +                memory: "64Mi"
    +            ports:
    +            - containerPort: 8080
    +            volumeMounts:
    +            - name: quota
    +              mountPath: /quota
    +          volumes:
    +          - name: quota
    +            configMap:
    +              name: quota
    +          - name: users
    +            secret:
    +              secretName: users
    +
    +  - kind: DeploymentConfig
    +    apiVersion: v1
    +    metadata:
    +      name: moon-ui
    +    spec:
    +      replicas: 1
    +      template:
    +        metadata:
    +          labels:
    +            app: moon-ui
    +        spec:
    +          containers:
    +            - name: moon-ui
    +              args:
    +                - '--selenoid-uri'
    +                - 'http://moon-api:8080'
    +              image: ${MOON_UI_IMAGE}
    +              ports:
    +                - containerPort: 8080
    +                  protocol: TCP
    +              resources:
    +                limits:
    +                  cpu: 100m
    +                  memory: 64M
    +
    +parameters:
    +- name: NAMESPACE
    +  displayName: Namespace
    +  description: Namespace where the Moon is running
    +  value: default
    +  required: true
    +
    +- name: MOON_IMAGE
    +  displayName: Moon docker image
    +  description: Name of the image to be used.
    +  value: aerokube/moon:latest-release
    +  required: true
    +
    +- name: MOON_API_IMAGE
    +  displayName: Moon-API docker image
    +  description: Name of the image to be used.
    +  value: aerokube/moon-api:latest-release
    +  required: true
    +
    +- name: MOON_UI_IMAGE
    +  displayName: Moon-UI docker image
    +  description: Name of the image to be used.
    +  value: aerokube/selenoid-ui:latest-release
    +  required: true
    +
    +- name: MOON_PODS
    +  displayName: Max moon pods in project
    +  description: Specify max moon pods for project (4 free slots + Moon + Moon API + Moon UI = 7).
    +  value: '7'
    +  required: true
    +
    @@ -2691,7 +3651,7 @@

    2