diff --git a/docker-compose.accounts.yml b/docker-compose.accounts.yml index 7cae6a92..2f000764 100644 --- a/docker-compose.accounts.yml +++ b/docker-compose.accounts.yml @@ -15,6 +15,10 @@ services: depends_on: - accounts + health-check: + environment: + - ACCOUNTS_ENABLED=1 + accounts: build: context: ./docker/accounts diff --git a/docker-compose.yml b/docker-compose.yml index 65a30ed6..5bce9f2c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -80,7 +80,6 @@ services: - 80 depends_on: - sia - - health-check - handshake-api - website @@ -155,12 +154,12 @@ services: networks: shared: ipv4_address: 10.10.10.60 + env_file: + - .env environment: - HOSTNAME=0.0.0.0 - - PORTAL_URL=http://nginx - STATE_DIR=/usr/app/state expose: - 3100 depends_on: - - handshake - - handshake-api + - caddy diff --git a/docker/kratos/oathkeeper/access-rules.yml b/docker/kratos/oathkeeper/access-rules.yml index d2fdb89d..a45f75b2 100644 --- a/docker/kratos/oathkeeper/access-rules.yml +++ b/docker/kratos/oathkeeper/access-rules.yml @@ -65,7 +65,7 @@ preserve_host: true url: "http://accounts:3000" match: - url: "http://oathkeeper<{,:4455}>/<{stripe/prices,stripe/webhook}>" + url: "http://oathkeeper<{,:4455}>/<{health,stripe/prices,stripe/webhook}>" methods: - GET - POST diff --git a/packages/health-check/Dockerfile b/packages/health-check/Dockerfile index 17771175..4bcd99b7 100644 --- a/packages/health-check/Dockerfile +++ b/packages/health-check/Dockerfile @@ -12,4 +12,4 @@ RUN echo '0 * * * * /usr/app/cli/run extended > /dev/stdout' >> /etc/crontabs/ro EXPOSE 3100 ENV NODE_ENV production -CMD [ "sh", "-c", "crond ; node --max-http-header-size=64000 src/index.js" ] +CMD [ "sh", "-c", "crond ; echo $(node src/whatismyip.js) siasky.net account.siasky.net >> /etc/hosts ; node --max-http-header-size=64000 src/index.js" ] diff --git a/packages/health-check/src/checks/critical.js b/packages/health-check/src/checks/critical.js index ed2b8f22..4fe48f39 100644 --- a/packages/health-check/src/checks/critical.js +++ b/packages/health-check/src/checks/critical.js @@ -7,26 +7,28 @@ const { calculateElapsedTime, getResponseContent } = require("../utils"); async function uploadCheck(done) { const time = process.hrtime(); const form = new FormData(); - const data = Buffer.from(new Date()); // current date to ensure data uniqueness + const payload = Buffer.from(new Date()); // current date to ensure data uniqueness + const data = { up: false }; - form.append("file", data, { filename: "time.txt", contentType: "text/plain" }); - let statusCode, errorResponseContent; + form.append("file", payload, { filename: "time.txt", contentType: "text/plain" }); try { - const response = await got.post(`${process.env.PORTAL_URL}/skynet/skyfile`, { body: form }); + const response = await got.post(`${process.env.SKYNET_PORTAL_API}/skynet/skyfile`, { body: form }); - statusCode = response.statusCode; + data.statusCode = response.statusCode; + data.up = true; + data.ip = response.ip; } catch (error) { - statusCode = error?.response?.statusCode || error.statusCode || error.status; - errorResponseContent = getResponseContent(error?.response); + data.statusCode = error.response?.statusCode || error.statusCode || error.status; + data.errorMessage = error.message; + data.errorResponseContent = getResponseContent(error.response); + data.ip = error?.response?.ip ?? null; } done({ name: "upload_file", - up: statusCode === StatusCodes.OK, - statusCode, - errorResponseContent, time: calculateElapsedTime(time), + ...data, }); } @@ -34,26 +36,57 @@ async function uploadCheck(done) { async function downloadCheck(done) { const time = process.hrtime(); const skylink = "AACogzrAimYPG42tDOKhS3lXZD8YvlF8Q8R17afe95iV2Q"; - let statusCode, errorMessage, errorResponseContent; + const data = { up: false }; try { - const response = await got(`${process.env.PORTAL_URL}/${skylink}?nocache=true`); + const response = await got(`${process.env.SKYNET_PORTAL_API}/${skylink}?nocache=true`); - statusCode = response.statusCode; + data.statusCode = response.statusCode; + data.up = true; + data.ip = response.ip; } catch (error) { - statusCode = error?.response?.statusCode || error.statusCode || error.status; - errorMessage = error.message; - errorResponseContent = getResponseContent(error.response); + data.statusCode = error?.response?.statusCode || error.statusCode || error.status; + data.errorMessage = error.message; + data.errorResponseContent = getResponseContent(error.response); + data.ip = error?.response?.ip ?? null; } done({ name: "download_file", - up: statusCode === StatusCodes.OK, - statusCode, - errorMessage, - errorResponseContent, time: calculateElapsedTime(time), + ...data, }); } -module.exports = [uploadCheck, downloadCheck]; +async function accountHealthCheck(done) { + const time = process.hrtime(); + const data = { up: false }; + + try { + const response = await got(`${process.env.SKYNET_DASHBOARD_URL}/health`, { responseType: "json" }); + + data.statusCode = response.statusCode; + data.response = response.body; + data.up = response.body.dbAlive === true; + data.ip = response.ip; + } catch (error) { + data.statusCode = error?.response?.statusCode || error.statusCode || error.status; + data.errorMessage = error.message; + data.errorResponseContent = getResponseContent(error.response); + data.ip = error?.response?.ip ?? null; + } + + done({ + name: "account_health", + time: calculateElapsedTime(time), + ...data, + }); +} + +const checks = [uploadCheck, downloadCheck]; + +if (process.env.ACCOUNTS_ENABLED) { + checks.push(accountHealthCheck); +} + +module.exports = checks; diff --git a/packages/health-check/src/checks/extended.js b/packages/health-check/src/checks/extended.js index d742f002..e9fa75c3 100644 --- a/packages/health-check/src/checks/extended.js +++ b/packages/health-check/src/checks/extended.js @@ -1059,7 +1059,7 @@ async function skylinkVerification(done, expected, { followRedirect = true, meth const details = { name: expected.name, skylink: expected.skylink }; try { - const query = `${process.env.PORTAL_URL}/${expected.skylink}`; + const query = `${process.env.SKYNET_PORTAL_API}/${expected.skylink}`; const response = await got[method](query, { followRedirect, headers: { cookie: "nocache=true" } }); const entry = { ...details, up: true, statusCode: response.statusCode, time: calculateElapsedTime(time) }; const info = {}; diff --git a/packages/health-check/src/index.js b/packages/health-check/src/index.js index 45c49572..a49ee81c 100644 --- a/packages/health-check/src/index.js +++ b/packages/health-check/src/index.js @@ -1,7 +1,11 @@ process.env.NODE_ENV = process.env.NODE_ENV || "development"; -if (!process.env.PORTAL_URL) { - throw new Error("You need to provide PORTAL_URL environment variable"); +if (!process.env.SKYNET_PORTAL_API) { + throw new Error("You need to provide SKYNET_PORTAL_API environment variable"); +} + +if (process.env.ACCOUNTS_ENABLED && !process.env.SKYNET_DASHBOARD_URL) { + throw new Error("You need to provide SKYNET_DASHBOARD_URL environment variable when accounts are enabled"); } const express = require("express"); diff --git a/packages/health-check/src/run.js b/packages/health-check/src/run.js index 577fdaf6..829a3c48 100644 --- a/packages/health-check/src/run.js +++ b/packages/health-check/src/run.js @@ -12,7 +12,7 @@ require("yargs/yargs")(process.argv.slice(2)).command( }) .option("portal-url", { describe: "Skynet portal url", - default: process.env.PORTAL_URL || "https://siasky.net", + default: process.env.SKYNET_PORTAL_API || "https://siasky.net", type: "string", }) .option("state-dir", { @@ -22,7 +22,7 @@ require("yargs/yargs")(process.argv.slice(2)).command( }); }, async ({ type, portalUrl, stateDir }) => { - process.env.PORTAL_URL = portalUrl; + process.env.SKYNET_PORTAL_API = portalUrl; process.env.STATE_DIR = stateDir; const db = require("../src/db"); diff --git a/packages/health-check/src/whatismyip.js b/packages/health-check/src/whatismyip.js new file mode 100644 index 00000000..b736be59 --- /dev/null +++ b/packages/health-check/src/whatismyip.js @@ -0,0 +1,13 @@ +const http = require("http"); + +const request = http.request({ host: "whatismyip.akamai.com" }, (response) => { + response.on("data", (data) => { + process.stdout.write(data); + }); +}); + +request.on("error", (error) => { + console.error(error); +}); + +request.end();