Skip to content

Commit

Permalink
feat: Adds agent-hub and runner-hub and run-in-batch cli arg (#169)
Browse files Browse the repository at this point in the history
* wip: hub agent/runner communicating through the same socket

* fix: upload benchmark file when start running

* fix: add spec config for the hubs, also changes config

* fix: simplify server logic

* feat: auth in hub based on jsonwebtoken

* feat: add README md

* feat: add agents api: add endpoint

* feat: add config in the example config

* feat: autoregister agent with hub

* fix: better messages for agent registration

* Revert "wip: one at the time crazyness"

This reverts commit 5739bbf8ea734074661d066c2a8291b4acc0d499.

* feat: add runInBatch option

to run builds in batches in the runner

* wip: working state check point

* fix: refactor hub runner

adds cancel timeout in agent

* fix: upload jobs to random folder to avoid collisions

* feat: start using the agent as soon as is added to the hub

* fix: remove extra abstraction on socket

* fix: lint errors
  • Loading branch information
jodarove committed Jul 3, 2019
1 parent 788844d commit 45d96cc
Show file tree
Hide file tree
Showing 37 changed files with 1,819 additions and 17 deletions.
174 changes: 174 additions & 0 deletions packages/@best/agent-hub/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Best Hub

A best hub represents a remote runner who relies/abstract other best-agents. These are the main benefits of using the agent hub:

1. Abstract clients (projects using best) from configuring specific remotes: you just need the hub address, an authorization token, and specify the browser name and version to run the tests.
2. Allows to run concurrently multiple benchmarks, improving performance on projects with many measures.
3. Allows to share resources among different projects: Ex: suppose you have project A, B and C. for each one you have a dedicated chrome best agent running (mA, mB, mC). Project X will always run in machine mX. With the hub, these 3 machines can be shared, and jobs from A, B and C can run in the hub.

## Getting Started

### Starting the hub

To start the hub server, simply run in your command line:

```bash
node bin/best-agent-hub.js
```

This command will start the hub server using the following configuration:

- Running port: `6000`. It can be overridden by setting `env.PORT` to the desired port.
- Tokens secret: `secret`. It's recommended to override it by setting `env.TOKEN_SECRET` to the desired secret used authenticate clients. See [Generating hub access tokens for clients](#generating-hub-access-tokens-for-clients).

### Configuring hub in startup.

You can configure a preset of agents when the hub starts by setting `env.CONFIG` to a json string representing the config for the hub.

The configuration of the hub is an array of hubs agents. Each agent represents a remote best agent like:

```javascript
const config = {
agents: [
{
spec: {
browser: "chrome", // Browser name
version: "76" // Browser version (major)
},
host: "http://localhost:5000", // Required. Url used to connect to the agent.
options: { path: "/best" }, // Connection
remoteRunner: "@best/runner-headless", // Required. The runner which the agent will use when running the job.
remoteRunnerConfig: {}, // Required (may be an empty object). The Runner config for the remote runner in the agent.
},
{
spec: {
browser: "ie",
version: "11"
},
host: "http://127.0.0.1:5002",
options: { path: "/best" },
remoteRunner: "@best/runner-webdriver",
remoteRunnerConfig: {
"webdriverOptions": {
"desiredCapabilities": {
"platform": "WINDOWS",
"browserName": "internet explorer",
"version": "11",
"ignoreZoomSetting": true,
"initialBrowserUrl": "about:blank",
"nativeEvents": false,
}
}
},
}
]
}

// set env.CONFIG=JSON.stringify(config);
```

**Note:** All agents with the same spec, should have the same configuration and hardware characteristics, this must be ensured given that a job to be run with these specs, can run in any of the agents, and they should return same results.

## How to use the hub your project

Add a new runner config section on your best.config:

```javascript
// Replace this token with a generated one for the used TOKEN_SECRET when starting the hub server
const hubAuthenticationToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6ImNsaWVudCIsImlhdCI6MTU2MTYwNzI1OCwiZXhwIjoxNTY0MTk5MjU4fQ.BER-PIIlsf6NWNBctWrmS1YWB4QkI2aYiNp0BE6aASU';

module.exports = {
projectName: 'simple-benchmark-chrome',
benchmarkOnClient: true,
"runnerConfig": [
{
"runner": "@best/runner-headless",
"alias": "default"
},
// Configs to use the hub
{
"runner": "@best/runner-hub",
"alias": "hub-chrome",
"config": {
"host": "http://localhost:6000",
"options": {
path: "/hub",
query: {
token: hubAuthenticationToken
}
},
"spec": {
"browser": "chrome",
"version": "76"
}
}
},
{
"runner": "@best/runner-hub",
"alias": "hub-ie11",
"config": {
"host": "http://localhost:6000",
"options": {
path: "/hub",
query: {
token: hubAuthenticationToken
}
},
"spec": {
"browser": "ie",
"version": "11"
}
}
},
],
};
```

Then you can run your measures in your project:

```bash
# Measures in chrome:
best --runner hub-chrome

# Measures in ie11:
best --runner hub-ie11
```

### Generating hub access tokens for clients

The hub authentication is based on [JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) standard using (https://github.com/auth0/node-jsonwebtoken)

Once you start your hub using a TOKEN_SECRET (for example: password) you will need to generate a token for the client connecting the hub. You can do that using the `generate-client-token` tool included with the `@best/agent-hub`

To display the help on the tool run:
```bash
node bin/generate-client-token --help
```

Example using the tool: (generate a client token for the hub using `password` as secret, the token will expire in 45 days)

```bash
node bin/generate-client-token.js -s password -c --ttl "45 days"
```

### Adding agents to the hub once started

Once the hub has already started you can add agents by doing a post request to `/api/v1/agents`. Example:

```bash
curl -X POST \
http://localhost:6000/api/v1/agents \
-H 'authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6ImFnZW50IiwiaWF0IjoxNTYxNjE0MjM3LCJleHAiOjE1NzcxNjYyMzd9.IjdCBSPPIGSgpYHN8Pxhusaiv48T1t6rmxR2xzdp17M' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d '{
"host":"http://localhost:5000",
"options":{"path":"/best"},
"remoteRunner":"@best/runner-headless",
"remoteRunnerConfig":{},
"spec": {
"browser": "chrome",
"version": "76"
}
}'
```
7 changes: 7 additions & 0 deletions packages/@best/agent-hub/bin/best-agent-hub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env node

if (process.env.NODE_ENV == null) {
process.env.NODE_ENV = 'perf';
}

require('../build/cli').run();
45 changes: 45 additions & 0 deletions packages/@best/agent-hub/bin/generate-client-token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env node

const argv = require('yargs')
.usage('Usage: $0 <command> [options]')
.command('gen-token', 'Generates hub access tokens')
.example('$0 gen -s hubSecret -c', 'Generates a key for a client')
.alias('s', 'secret')
.alias('c', 'client')
.alias('a', 'agent')
.alias('t', 'ttl')
.nargs('s', 1)
.describe('s', 'Hub secret')
.describe('c', 'If this key is meant to be used by a client accessing the hub. Is exclusive with option "a". Defaults true')
.describe('a', 'If this key is meant to be used by an agent accessing the hub')
.describe('t', 'Time to live for the token in zeit/ms (check https://github.com/zeit/ms). For clients default is 30 days, for agents 180 days.')
.demandOption(['s'])
.boolean('c').default('c', true)
.boolean('a').default('a', false)
.string('t')
.help('h')
.alias('h', 'help')
.epilog('copyright 2019')
.argv;

const payload = {
scope: 'client'
};
let ttl = argv.ttl || '30 days';

if (argv.agent) {
payload.scope = 'agent';
ttl = argv.ttl || '180 days';
}

// nothing to do for client since has the defaults.

const jwt = require('jsonwebtoken');

const token = jwt.sign(
payload,
argv.secret,
{ expiresIn: ttl }
);

console.log(token);
21 changes: 21 additions & 0 deletions packages/@best/agent-hub/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@best/agent-hub",
"version": "4.0.0",
"description": "Best Agent Hub",
"keywords": [
"Best",
"performance",
"Hub"
],
"main": "build/cli/index.js",
"dependencies": {
"@best/runner-remote": "4.0.0",
"@best/utils": "4.0.0",
"jsonwebtoken": "^8.5.1",
"@types/jsonwebtoken": "^8.3.2",
"express": "~4.16.2",
"socket.io": "~2.2.0",
"socket.io-file": "~2.0.31",
"yargs": "^13.2.4"
}
}
Loading

0 comments on commit 45d96cc

Please sign in to comment.