diff --git a/CHANGELOG.md b/CHANGELOG.md index 36cd82e6..70e87013 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Apps with a container check no longer show an unhealthy badge while Docker + container health checks are off. + +- An app's health check can be turned off while Docker container health checks + are off. + - A widget's settings now open from that widget's own saved config. - A tile with only a fixed label set now shows that badge. diff --git a/api/src/routes/health.js b/api/src/routes/health.js index 7821edb9..820236c4 100644 --- a/api/src/routes/health.js +++ b/api/src/routes/health.js @@ -20,10 +20,11 @@ const demoData = require('../demo-data'); const log = require('../log'); const SOCKET_PROXY_URL_DEFAULT = process.env.SOCKET_PROXY_URL || ''; -async function fetchContainerHealth() { - const cfg = loadConfig(); - const socketUrl = cfg.settings?.server?.socketProxyUrl || SOCKET_PROXY_URL_DEFAULT; - if (!socketUrl) return Object.create(null); +function socketProxyUrl(cfg) { + return cfg.settings?.server?.socketProxyUrl || SOCKET_PROXY_URL_DEFAULT; +} + +async function fetchContainerHealth(socketUrl) { try { const r = await fetchUnchecked(`${socketUrl}/containers/json?all=true`); if (!Array.isArray(r.data)) return Object.create(null); @@ -133,15 +134,18 @@ on('GET', '/api/health', async (req, res) => { const cfg = loadConfig(); return json(res, 200, demoData.demoHealth(cfg.items)); } - const containers = await fetchContainerHealth(); - const cfg = loadConfig(), - result = Object.create(null); + const cfg = loadConfig(); + const socketUrl = socketProxyUrl(cfg); + /* Without a proxy address every container lookup misses, which would report + every container-backed app as unhealthy. */ + const containers = socketUrl ? await fetchContainerHealth(socketUrl) : Object.create(null); + const result = Object.create(null); await Promise.allSettled( cfg.items .filter(i => i.type === 'app' && (i.container || i.ping || i.monitoring?.healthcheck?.enabled)) .map(async item => { const mon = item.monitoring?.healthcheck || {}; - const cName = mon.container || item.container || ''; + const cName = socketUrl ? mon.container || item.container || '' : ''; const ping = mon.pingUrl || item.ping || ''; /* Build the entry up rather than replace it. An item can have both a container and a ping, and the tile needs the detail from each. */ @@ -170,7 +174,7 @@ on('GET', '/api/health', async (req, res) => { detail.pingStatus = r.status; detail.pingError = r.error; } - result[item.id] = { unhealthy, ...detail }; + if (cName || ping) result[item.id] = { unhealthy, ...detail }; }), ); json(res, 200, result); diff --git a/api/test/health-route.test.js b/api/test/health-route.test.js index ee25ad1b..aba2b8e7 100644 --- a/api/test/health-route.test.js +++ b/api/test/health-route.test.js @@ -2,6 +2,7 @@ const path = require('node:path'); const { tmpDir } = require('../test-support/tmp'); process.env.CONFIG_PATH = path.join(tmpDir('health'), 'apps.json'); +delete process.env.SOCKET_PROXY_URL; const { test, before, after } = require('node:test'); const assert = require('node:assert/strict'); @@ -62,10 +63,10 @@ function health() { }); } -function configure(item) { +function configure(item, socketProxyUrl = socketBase) { saveConfig({ items: [Object.assign({ id: 'a1', type: 'app', name: 'App' }, item)], - settings: { server: { socketProxyUrl: socketBase } }, + settings: { server: { socketProxyUrl } }, }); } @@ -157,3 +158,19 @@ test('a container actually named __proto__ is matched, not discarded', async () assert.equal(r.unhealthy, true); assert.equal(r.state, 'exited'); }); + +test('a container check is skipped while no socket proxy is configured', async () => { + containers = []; + configure({ container: 'myapp', monitoring: { healthcheck: { enabled: true, container: 'myapp' } } }, ''); + assert.equal((await health()).a1, undefined); +}); + +test('a ping check still runs while no socket proxy is configured', async () => { + containers = []; + targetStatus = 200; + configure({ container: 'myapp', ping: `${targetBase}/` }, ''); + const r = (await health()).a1; + assert.equal(r.unhealthy, false); + assert.equal(r.pingStatus, 200); + assert.equal(r.state, undefined); +}); diff --git a/ui/admin/index.html b/ui/admin/index.html index a5b14afe..e83f5eee 100644 --- a/ui/admin/index.html +++ b/ui/admin/index.html @@ -303,6 +303,6 @@