From 21d651b8971628d30a2fe5f1d36bba7c214881d0 Mon Sep 17 00:00:00 2001 From: Aaron Williams Date: Tue, 1 Mar 2022 13:38:29 +1000 Subject: [PATCH] Use Promise.allSettled instead of Promise.all This allows for any hosts that are able to be resolved to still function correctly while any that don't will throw an error --- controllers/apps/docker/useDocker.js | 222 ++++++++++++++------------- 1 file changed, 116 insertions(+), 106 deletions(-) diff --git a/controllers/apps/docker/useDocker.js b/controllers/apps/docker/useDocker.js index db7d632..815ba77 100644 --- a/controllers/apps/docker/useDocker.js +++ b/controllers/apps/docker/useDocker.js @@ -4,135 +4,145 @@ const Logger = require('../../../utils/Logger'); const logger = new Logger(); const loadConfig = require('../../../utils/loadConfig'); +async function getContainer ({ host }) { + const isLocalhost = host.includes('localhost'); + try { + return await axios.get( + `http://${host}/containers/json?{"status":["running"]}`, + isLocalhost ? { + socketPath: '/var/run/docker.sock', + } : {} + ) + } catch { + const error = `Can't connect to the Docker API on the host ${host}`; + logger.log(error, 'ERROR'); + throw new Error(error) + } +} + const useDocker = async (apps) => { const { useOrdering: orderType, unpinStoppedApps, - dockerHost: host, + dockerHost: host = '', } = await loadConfig(); - let containers = [] - const hosts = host.split(';'); + const hosts = host.split(';') + const hostRequests = await Promise.allSettled(hosts.map((host) => getContainer({ host }))) - try { - // Get list of containers - containers = (await Promise.all(hosts.reduce((acc, host) => { - const isLocalhost = host.includes('localhost'); - acc.push(axios.get( - `http://${host}/containers/json?{"status":["running"]}`, - isLocalhost ? { - socketPath: '/var/run/docker.sock', - } : {} - )) - return acc; - }, []))).flatMap(({ data }) => data) - } catch (err) { - logger.log(`Can't connect to the Docker API on one of the hosts: ${hosts.join(', ')}`, 'ERROR'); - } + if (hostRequests.length > 0) { + let containers = hostRequests + // Extract successful requests to docker socket + .reduce((acc, { status, value }) => { + if (status === 'fulfilled') { + acc = acc.concat(value.data) + } + return acc; + }, []) + // Filter out containers without any annotations + .filter((e) => Object.keys(e.Labels).length !== 0) - if (containers.length > 0) { - apps = await App.findAll({ - order: [[orderType, 'ASC']], - }); + if (containers.length > 0) { + apps = await App.findAll({ + order: [[orderType, 'ASC']], + }); - // Filter out containers without any annotations - containers = containers.filter((e) => Object.keys(e.Labels).length !== 0); + const dockerApps = []; - const dockerApps = []; + for (const container of containers) { + let labels = container.Labels; - for (const container of containers) { - let labels = container.Labels; - - // Traefik labels for URL configuration - if (!('flame.url' in labels)) { - for (const label of Object.keys(labels)) { - if (/^traefik.*.frontend.rule/.test(label)) { - // Traefik 1.x - let value = labels[label]; - - if (value.indexOf('Host') !== -1) { - value = value.split('Host:')[1]; - labels['flame.url'] = - 'https://' + value.split(',').join(';https://'); - } - } else if (/^traefik.*?\.rule/.test(label)) { - // Traefik 2.x - const value = labels[label]; - - if (value.indexOf('Host') !== -1) { - const regex = /\`([a-zA-Z0-9\.\-]+)\`/g; - const domains = []; - - while ((match = regex.exec(value)) != null) { - domains.push('http://' + match[1]); + // Traefik labels for URL configuration + if (!('flame.url' in labels)) { + for (const label of Object.keys(labels)) { + if (/^traefik.*.frontend.rule/.test(label)) { + // Traefik 1.x + let value = labels[label]; + + if (value.indexOf('Host') !== -1) { + value = value.split('Host:')[1]; + labels['flame.url'] = + 'https://' + value.split(',').join(';https://'); } - - if (domains.length > 0) { - labels['flame.url'] = domains.join(';'); + } else if (/^traefik.*?\.rule/.test(label)) { + // Traefik 2.x + const value = labels[label]; + + if (value.indexOf('Host') !== -1) { + const regex = /\`([a-zA-Z0-9\.\-]+)\`/g; + const domains = []; + + while ((match = regex.exec(value)) != null) { + domains.push('http://' + match[1]); + } + + if (domains.length > 0) { + labels['flame.url'] = domains.join(';'); + } } } } } - } - - // add each container as flame formatted app - if ( - 'flame.name' in labels && - 'flame.url' in labels && - /^app/.test(labels['flame.type']) - ) { - for (let i = 0; i < labels['flame.name'].split(';').length; i++) { - const names = labels['flame.name'].split(';'); - const urls = labels['flame.url'].split(';'); - let icons = ''; - - if ('flame.icon' in labels) { - icons = labels['flame.icon'].split(';'); - } - - dockerApps.push({ - name: names[i] || names[0], - url: urls[i] || urls[0], - icon: icons[i] || 'docker', - }); - } - } - } - - if (unpinStoppedApps) { - for (const app of apps) { - await app.update({ isPinned: false }); - } - } - - for (const item of dockerApps) { - // If app already exists, update it - if (apps.some((app) => app.name === item.name)) { - const app = apps.find((a) => a.name === item.name); - + + // add each container as flame formatted app if ( - item.icon === 'custom' || - (item.icon === 'docker' && app.icon != 'docker') + 'flame.name' in labels && + 'flame.url' in labels && + /^app/.test(labels['flame.type']) ) { - // update without overriding icon - await app.update({ - name: item.name, - url: item.url, - isPinned: true, - }); + for (let i = 0; i < labels['flame.name'].split(';').length; i++) { + const names = labels['flame.name'].split(';'); + const urls = labels['flame.url'].split(';'); + let icons = ''; + + if ('flame.icon' in labels) { + icons = labels['flame.icon'].split(';'); + } + + dockerApps.push({ + name: names[i] || names[0], + url: urls[i] || urls[0], + icon: icons[i] || 'docker', + }); + } + } + } + + if (unpinStoppedApps) { + for (const app of apps) { + await app.update({ isPinned: false }); + } + } + + for (const item of dockerApps) { + // If app already exists, update it + if (apps.some((app) => app.name === item.name)) { + const app = apps.find((a) => a.name === item.name); + + if ( + item.icon === 'custom' || + (item.icon === 'docker' && app.icon != 'docker') + ) { + // update without overriding icon + await app.update({ + name: item.name, + url: item.url, + isPinned: true, + }); + } else { + await app.update({ + ...item, + isPinned: true, + }); + } } else { - await app.update({ + // else create new app + await App.create({ ...item, + icon: item.icon === 'custom' ? 'docker' : item.icon, isPinned: true, }); } - } else { - // else create new app - await App.create({ - ...item, - icon: item.icon === 'custom' ? 'docker' : item.icon, - isPinned: true, - }); } } }