Skip to content

Commit

Permalink
Merge pull request #2 from Bauer-Xcel-Media/development
Browse files Browse the repository at this point in the history
Post review fixes
  • Loading branch information
valdemon authored Oct 23, 2018
2 parents 5e0a80c + f6dee7b commit 7bb477f
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 34 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,5 @@ deploy:
skip_cleanup: true
script:
- npx travis-deploy-once "npx semantic-release"
on:
branch: master
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ A [Node.js](https://nodejs.org) implementation of the [Health Checks API](https:
- [Functionality](#functionality)
- [Health status reports](#health-status-reports)
- [Usage](#usage)
- [Service details (`about` endpoint)](#service-details-about-endpoint)
- [Configuration](#configuration)
- [Example - Express.js powered application](#example---expressjs-powered-application)
- [Check types](#check-types)
- [`self` check](#self-check)
Expand Down Expand Up @@ -106,6 +108,34 @@ The overall health state of the subject service/application is an aggregation of
The module works as a middleware, exposing the [Health Checks API](https://hootsuite.github.io/health-checks-api/) routes via chosen `http server` framework routing system.
### Service details (`about` endpoint)
The [Health Checks API `about` endpoint](https://hootsuite.github.io/health-checks-api/#status-about-get) is supposed to describe the underlying service using this module.
The module takes particular service description attributes either from the [Configuration](#configuration) or mapping them from the service's [package.json](https://docs.npmjs.com/files/package.json) as a fallback. When particular attribute is missing both in the service config and in `package.json` a default value is taken, when provided.
Here is the table with particular fields, their mapping to config attributes and fallback mapping to `package.json` and optional defaults:
| _Attribute name_ | _Config attribute name_ | _`package.json` fallback - attribute mapping_ | _Static or dynamic fallback (defaults)_ |
|------------------|-------------------------|------------------------------------------------|-----------------------------------------|
| id | name | name | - |
| name | name | name | - |
| description | description | description | - |
| version | version | version | 'x.x.x' |
| host | host | - | require('os').hostname() |
| protocol | protocol | - | 'http' |
| projectHome | projectHome | homepage | - |
| projectRepo | projectRepo | repository.url | 'unknown' |
| owners | owners | author + contributors | - |
| logsLinks | logsLinks | - | - |
| statsLinks | statsLinks | - | - |
| dependencies | checks | - | - |
> __NOTE__
>
> _The final value is resolved with a fallback from left to right, as presented in above table._
### Configuration
The module configuration is a single `yaml` file and represents the subject service/application context.
The default path for the config file is `./conf/dependencies.yml`.
Expand Down
7 changes: 4 additions & 3 deletions lib/checks/self.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ const utils = require('../utils');
module.exports = class Self extends Check {
constructor(config) {
super(config);
this.config.type = 'internal';
this.config.type = constants.SERVICE_TYPE_INTERNAL;
this.config.url = '127.0.0.1';
this.config.name = 'self-check';
this.config.statusPath = 'self-check';
this.config.name = constants.SELF_CHECK_ID;
this.id = constants.SELF_CHECK_ID;
this.config.statusPath = constants.SELF_CHECK_ID;
this.status = [ constants.OK ];
this.metrics = this.config.metrics || Object.assign({}, constants.DEFAULT_METRICS_LIMITS);
this.secondsToKeepMemoryLeakMsg =
Expand Down
14 changes: 12 additions & 2 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@ const HEALTH_STATUSES = [ OK, WARN, CRIT ];

const TIME_FACTOR = 0.001;

const SERVICE_TYPE_INTERNAL = 'internal';
const SERVICE_TYPE_EXTERNAL = 'external';

const DEFAULT_INTERVAL = 3000;
const DEFAULT_CONFIG_PATH = './conf/dependencies.yml';
const DEFAULT_TIMEOUT = 2000;
const DEFAULT_SERVICE_TYPE = 'external';
const DEFAULT_SERVICE_TYPE = SERVICE_TYPE_EXTERNAL;
const DEFAULT_ADAPTER = 'express';
const DEFAULT_METRICS_LIMITS = {
cpuUsage: {
Expand Down Expand Up @@ -43,7 +46,7 @@ const MSG_NO_DESCRIPTION = 'No description provided.';
const MSG_MEMORY_LEAK_DETECTED = 'Memory leak detected!';
const MSG_ADAPTER_MUST_BE_A_FUNCTION =
'Given \'adapter\' parameter must be either a function or a name of a module exporting a function.';
const MSG_UNKNOWN_STATUS_ENDPOINT = 'Unknow status endpoint';
const MSG_UNKNOWN_STATUS_ENDPOINT = 'Unknown status endpoint';
const MSG_UNKNOWN_STATUS_ENDPOINT_DETAILS = 'Status endpoint does not exist: /status/';
const MSG_CANT_TRAVERSE = 'Can\'t traverse';
const MSG_IS_NOT_TRAVERSEABLE = 'is not traversable';
Expand All @@ -52,6 +55,8 @@ const HEADER_X_FORWARDED_FOR = 'x-forwarded-for';
const HEADER_X_FORWARDED_PROTO = 'x-forwarded-proto';
const HEADER_CONTENT_TYPE = 'content-type';

const SELF_CHECK_ID = 'self-check';

module.exports = {
OK,
WARN,
Expand Down Expand Up @@ -86,4 +91,9 @@ module.exports = {
HEADER_X_FORWARDED_FOR,
HEADER_X_FORWARDED_PROTO,
HEADER_CONTENT_TYPE,

SELF_CHECK_ID,

SERVICE_TYPE_INTERNAL,
SERVICE_TYPE_EXTERNAL,
};
28 changes: 16 additions & 12 deletions lib/routes/about.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
'use strict';

const os = require('os');
const httpStatus = require('http-status');
const constants = require('../constants');

const getServiceUrl = params => {
const host = params[constants.HEADER_X_FORWARDED_FOR] || params.host;
const proto = params[constants.HEADER_X_FORWARDED_PROTO] || constants.DEFAULT_PROTOCOL;
return `${proto}://${host}`;
const authors = packageJson => {
let result = [];
if (packageJson.author) {
result.push(packageJson.author);
}
if (packageJson.contributors) {
result = result.concat(packageJson.contributors);
}
return result.map(person => person.name ? `${person.name} <${person.email}>` : person);
};

module.exports = async (params, service) => ({
Expand All @@ -17,17 +23,15 @@ module.exports = async (params, service) => ({
id: service.config.name || service.packageJson.name,
name: service.config.name || service.packageJson.name,
description: service.config.description || service.packageJson.description,
version: service.packageJson.version || constants.DEFAULT_SERVICE_VERSION,
host: service.config.host || getServiceUrl(params),
protocol: service.config.protocol || params[constants.HEADER_X_FORWARDED_PROTO] || constants.DEFAULT_PROTOCOL,
version: service.config.version || service.packageJson.version || constants.DEFAULT_SERVICE_VERSION,
host: service.config.host || os.hostname(),
protocol: service.config.protocol || constants.DEFAULT_PROTOCOL,
projectHome: service.config.projectHome || service.packageJson.homepage,
projectRepo: service.config.projectRepo ||
(service.packageJson.repository ? service.packageJson.repository.url : constants.DEFAULT_SERVICE_REPO_URL),
owners: service.config.owners || [
service.packageJson.author && service.packageJson.author.name
? `${service.packageJson.author.name} <${service.packageJson.author.email}>`
: service.packageJson.author
],
owners: service.config.owners || authors(service.packageJson),
logsLinks: service.config.logsLinks,
statsLinks: service.config.statsLinks,
dependencies: service.checks.map(check => check.status),
},
});
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,14 @@
"keywords": [
"health",
"healthcheck",
"healthchecks",
"health-check",
"health-checks",
"microservice",
"microservices",
"hootsuite",
"health-checks-api"
"health-checks-api",
"healthchecks-api"
],
"devDependencies": {
"commitizen": "^3.0.2",
Expand Down
8 changes: 7 additions & 1 deletion test/integration/conf/demo-app.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
version: "3.1"

# the 'version' will be taken from the package.json

name: demo-app
description: Nice demo application :)
statsLinks:
- https://my-stats/demo-app
logsLinks:
- https://my-logs/demo-app/info
- https://my-logs/demo-app/debug

checks:
- check: self
Expand Down
8 changes: 6 additions & 2 deletions test/integration/conf/service-1.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
version: "3.1"
version: "3.0.1"

name: service-1
description: Service-1 awesome service
description: Awesome Service-1
statsLinks:
- https://my-stats/service-1
logsLinks:
- https://my-logs/service-1

checks:
- check: self
Expand Down
8 changes: 6 additions & 2 deletions test/integration/conf/service-2.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
version: "3.1"
version: "3.0.2"

name: service-2
description: Service-1 awesome service
description: Incredible Service-2
statsLinks:
- https://my-stats/service-2
logsLinks:
- https://my-logs/service-2

checks:
- check: self
Expand Down
8 changes: 6 additions & 2 deletions test/integration/conf/service-3.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
version: "3.1"
version: "3.0.3"

name: service-3
description: Service-1 awesome service
description: Outstanding Service-3
statsLinks:
- https://my-stats/service-3
logsLinks:
- https://my-logs/service-3

checks:
- check: self
Expand Down
5 changes: 5 additions & 0 deletions test/integration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.1.0",
"description": "",
"main": "service.js",
"homepage": "https://my-org/health-check-test-service",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node service.js"
Expand All @@ -19,6 +20,10 @@
"url": "https://github.com/valdemon"
}
],
"repository": {
"type": "git",
"url": "https://my-repo/health-check-test-service.git"
},
"license": "MIT",
"dependencies": {
"healthchecks-api": "../..",
Expand Down
7 changes: 4 additions & 3 deletions test/unit/checks/self.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ it ('should instantiate the Self check class properly with default options', asy
const testeeInstance = new Testee();
// uncomment following when https://github.com/facebook/jest/issues/2549 is solved.
// expect(testeeInstance).toBeInstanceOf(Check);
expect(testeeInstance.config.type).toBe('internal');
expect(testeeInstance.config.type).toBe(constants.SERVICE_TYPE_INTERNAL);
expect(testeeInstance.config.url).toBe('127.0.0.1');
expect(testeeInstance.config.name).toBe('self-check');
expect(testeeInstance.config.statusPath).toBe('self-check');
expect(testeeInstance.config.name).toBe(constants.SELF_CHECK_ID);
expect(testeeInstance.config.statusPath).toBe(constants.SELF_CHECK_ID);
expect(testeeInstance.id).toBe(constants.SELF_CHECK_ID);
expect(testeeInstance.status.status).toEqual([ constants.OK ]);
expect(testeeInstance.metrics).toEqual(constants.DEFAULT_METRICS_LIMITS);
expect(testeeInstance.secondsToKeepMemoryLeakMsg).toBe(constants.DEFAULT_SECONDS_TO_KEEP_MEMORY_LEAK_MSG);
Expand Down
24 changes: 19 additions & 5 deletions test/unit/routes/about.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const status = require('http-status');
const os = require('os');
const constants = require('../constants');
const testee = require('../../../lib/routes/about');

Expand Down Expand Up @@ -30,15 +31,18 @@ const check2 = {
};

it('should return a proper response when providing config data', async () => {
const host = 'localhost:9000';
const host = 'localhost';
const packageJson = {
author: 'John Doe',
};
const config = {
name: 'config_name',
host,
description: 'config_description',
projectHome: 'config_projectHome',
projectRepo: 'config_projectRepo',
logsLinks: [ 'some-link-1', 'some-link-2'],
statsLinks: [ 'some-link-3', 'some-link-4'],
};

return expect(testee({ host }, {
Expand All @@ -57,17 +61,23 @@ it('should return a proper response when providing config data', async () => {
}, config, {
id: config.name,
protocol: 'http',
host: `http://${host}`,
host,
version: constants.DEFAULT_SERVICE_VERSION,
owners: [ packageJson.author ],
logsLinks: config.logsLinks,
statsLinks: config.statsLinks,
}),
});
});

it('should return a proper response when providing package.json data', async () => {
const host = 'localhost:9000';
const host = 'localhost';
const packageJson = {
author: { name: 'John Doe', email: '[email protected]' },
contributors: [
'John Smith <[email protected]>',
{ name: 'Mary Smith', email: '[email protected]' }
],
name: 'config_name',
description: 'config_description',
homepage: 'config_projectHome',
Expand Down Expand Up @@ -95,9 +105,13 @@ it('should return a proper response when providing package.json data', async ()
description: packageJson.description,
id: packageJson.name,
protocol: 'http',
host: `http://${host}`,
host: os.hostname(),
version: constants.DEFAULT_SERVICE_VERSION,
owners: [ `${packageJson.author.name} <${packageJson.author.email}>` ],
owners: [
`${packageJson.author.name} <${packageJson.author.email}>`,
packageJson.contributors[0],
`${packageJson.contributors[1].name} <${packageJson.contributors[1].email}>`,
],
projectHome: packageJson.homepage,
projectRepo: packageJson.repository.url,
}),
Expand Down
3 changes: 2 additions & 1 deletion test/unit/routes/traverse.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const status = require('http-status');
const os = require('os');
const nock = require('nock');
const constants = require('../constants');
const testee = require('../../../lib/routes/traverse');
Expand Down Expand Up @@ -123,7 +124,7 @@ it('should return an \'about\' response when request paramete \'dependency\' is
}, config, {
id: config.name,
protocol: 'http',
host: `http://${host}`,
host: os.hostname(),
version: constants.DEFAULT_SERVICE_VERSION,
owners: [ packageJson.author ],
}),
Expand Down

0 comments on commit 7bb477f

Please sign in to comment.