diff --git a/src/apps.js b/src/apps.js index f3010161c..983aba8e5 100644 --- a/src/apps.js +++ b/src/apps.js @@ -218,7 +218,6 @@ function validatePortBindings(portBindings, manifest) { 993, /* imaps */ 995, /* pop3s */ 2003, /* graphite (lo) */ - 2004, /* graphite (lo) */ 2514, /* cloudron-syslog (lo) */ constants.PORT, /* app server (lo) */ constants.AUTHWALL_PORT, /* protected sites */ @@ -229,7 +228,6 @@ function validatePortBindings(portBindings, manifest) { 4190, /* managesieve */ 5349, /* turn,stun TLS */ 8000, /* ESXi monitoring */ - 8417, /* graphite (lo) */ ]; const RESERVED_PORT_RANGES = [ diff --git a/src/graphs.js b/src/graphs.js index 10198eae8..8cbd8989d 100644 --- a/src/graphs.js +++ b/src/graphs.js @@ -8,13 +8,23 @@ exports = module.exports = { const apps = require('./apps.js'), assert = require('assert'), BoxError = require('./boxerror.js'), + docker = require('./docker.js'), safe = require('safetydance'), superagent = require('superagent'), system = require('./system.js'); -// for testing locally: curl 'http://127.0.0.1:8417/graphite-web/render?format=json&from=-1min&target=absolute(collectd.localhost.du-docker.capacity-usage)' +// for testing locally: curl 'http://${graphite-ip}:8000/graphite-web/render?format=json&from=-1min&target=absolute(collectd.localhost.du-docker.capacity-usage)' // the datapoint is (value, timestamp) https://buildmedia.readthedocs.org/media/pdf/graphite/0.9.16/graphite.pdf -const GRAPHITE_RENDER_URL = 'http://127.0.0.1:8417/graphite-web/render'; +async function getGraphiteUrl() { + const [error, result] = await safe(docker.inspect('graphite')); + if (error && error.reason === BoxError.NOT_FOUND) return { status: exports.SERVICE_STATUS_STOPPED }; + if (error) throw error; + + const ip = safe.query(result, 'NetworkSettings.Networks.cloudron.IPAddress', null); + if (!ip) throw new BoxError(BoxError.INACTIVE, 'Error getting IP of graphite service'); + + return `http://${ip}:8000/graphite-web/render`; +} async function getByApp(app, fromMinutes, noNullPoints) { assert.strictEqual(typeof app, 'object'); @@ -22,6 +32,7 @@ async function getByApp(app, fromMinutes, noNullPoints) { assert.strictEqual(typeof noNullPoints, 'boolean'); const timeBucketSize = fromMinutes > (24 * 60) ? (6*60) : 5; + const graphiteUrl = await getGraphiteUrl(); const targets = [ `summarize(collectd.localhost.docker-stats-${app.id}.gauge-cpu-perc, "${timeBucketSize}min", "avg")`, @@ -44,11 +55,7 @@ async function getByApp(app, fromMinutes, noNullPoints) { noNullPoints: !!noNullPoints }; - const [error, response] = await safe(superagent.get(GRAPHITE_RENDER_URL) - .query(query) - .timeout(30 * 1000) - .ok(() => true)); - + const [error, response] = await safe(superagent.get(graphiteUrl).query(query).timeout(30 * 1000).ok(() => true)); if (error) throw new BoxError(BoxError.NETWORK_ERROR, error.message); if (response.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unknown error with ${target}: ${response.status} ${response.text}`); @@ -70,6 +77,7 @@ async function getSystem(fromMinutes, noNullPoints) { assert.strictEqual(typeof noNullPoints, 'boolean'); const timeBucketSize = fromMinutes > (24 * 60) ? (6*60) : 5; + const graphiteUrl = await getGraphiteUrl(); const cpuQuery = `summarize(sum(collectd.localhost.aggregation-cpu-average.cpu-system, collectd.localhost.aggregation-cpu-average.cpu-user), "${timeBucketSize}min", "avg")`; const memoryQuery = `summarize(collectd.localhost.memory.memory-used, "${timeBucketSize}min", "avg")`; @@ -81,11 +89,7 @@ async function getSystem(fromMinutes, noNullPoints) { until: 'now' }; - const [memCpuError, memCpuResponse] = await safe(superagent.get(GRAPHITE_RENDER_URL) - .query(query) - .timeout(30 * 1000) - .ok(() => true)); - + const [memCpuError, memCpuResponse] = await safe(superagent.get(graphiteUrl).query(query).timeout(30 * 1000).ok(() => true)); if (memCpuError) throw new BoxError(BoxError.NETWORK_ERROR, memCpuError.message); if (memCpuResponse.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unknown error: ${memCpuResponse.status} ${memCpuResponse.text}`); @@ -140,7 +144,7 @@ async function getSystem(fromMinutes, noNullPoints) { until: 'now' }; - const [diskError, diskResponse] = await safe(superagent.get(GRAPHITE_RENDER_URL).query(diskQuery).timeout(30 * 1000).ok(() => true)); + const [diskError, diskResponse] = await safe(superagent.get(graphiteUrl).query(diskQuery).timeout(30 * 1000).ok(() => true)); if (diskError) throw new BoxError(BoxError.NETWORK_ERROR, diskError.message); if (diskResponse.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unknown error: ${diskResponse.status} ${diskResponse.text}`); @@ -156,7 +160,7 @@ async function getSystem(fromMinutes, noNullPoints) { until: 'now' }; - const [error, response] = await safe(superagent.get(GRAPHITE_RENDER_URL).query(query).timeout(30 * 1000).ok(() => true)); + const [error, response] = await safe(superagent.get(graphiteUrl).query(query).timeout(30 * 1000).ok(() => true)); if (error) throw new BoxError(BoxError.NETWORK_ERROR, error.message); if (response.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unknown error: ${response.status} ${response.text}`); diff --git a/src/services.js b/src/services.js index f13cee15a..a3fd5372d 100644 --- a/src/services.js +++ b/src/services.js @@ -1646,6 +1646,7 @@ async function startGraphite(existingInfra) { const readOnly = !serviceConfig.recoveryMode ? '--read-only' : ''; const cmd = serviceConfig.recoveryMode ? '/bin/bash -c \'echo "Debug mode. Sleeping" && sleep infinity\'' : ''; + // port 2003 is used by collectd const runCmd = `docker run --restart=always -d --name="graphite" \ --hostname graphite \ --net cloudron \ @@ -1659,8 +1660,6 @@ async function startGraphite(existingInfra) { --dns 172.18.0.1 \ --dns-search=. \ -p 127.0.0.1:2003:2003 \ - -p 127.0.0.1:2004:2004 \ - -p 127.0.0.1:8417:8000 \ -v "${paths.PLATFORM_DATA_DIR}/graphite:/var/lib/graphite" \ --label isCloudronManaged=true \ ${readOnly} -v /tmp -v /run "${tag}" ${cmd}`; @@ -1883,7 +1882,10 @@ async function statusGraphite() { if (error && error.reason === BoxError.NOT_FOUND) return { status: exports.SERVICE_STATUS_STOPPED }; if (error) throw error; - const [networkError, response] = await safe(superagent.get('http://127.0.0.1:8417/graphite-web/dashboard') + const ip = safe.query(container, 'NetworkSettings.Networks.cloudron.IPAddress', null); + if (!ip) throw new BoxError(BoxError.INACTIVE, 'Error getting IP of graphite service'); + + const [networkError, response] = await safe(superagent.get(`http://${ip}:8000/graphite-web/dashboard`) .timeout(20000) .ok(() => true));