1
0
Fork 0
mirror of https://github.com/pawelmalak/flame.git synced 2025-07-31 00:19:36 +02:00

Merge branch 'master' of https://github.com/pawelmalak/flame into merge_upstream_2020-12-06

This commit is contained in:
François Darveau 2021-12-06 22:29:22 -05:00
commit 021bd4e85a
266 changed files with 13470 additions and 7067 deletions

View file

@ -0,0 +1,4 @@
module.exports = {
useKubernetes: require('./useKubernetes'),
useDocker: require('./useDocker'),
};

View file

@ -0,0 +1,176 @@
const App = require('../../../models/App');
const axios = require('axios');
const Logger = require('../../../utils/Logger');
const logger = new Logger();
const loadConfig = require('../../../utils/loadConfig');
dockerDefaultCategory = {
id: -2,
name: 'Docker',
type: 'apps',
isPinned: true,
orderId: 998,
};
const useDocker = async (apps) => {
const {
useOrdering: orderType,
unpinStoppedApps,
dockerHost: host,
} = await loadConfig();
let containers = null;
// Get list of containers
try {
if (host.includes('localhost')) {
// Use default host
let { data } = await axios.get(
`http://${host}/containers/json?{"status":["running"]}`,
{
socketPath: '/var/run/docker.sock',
}
);
containers = data;
} else {
// Use custom host
let { data } = await axios.get(
`http://${host}/containers/json?{"status":["running"]}`
);
containers = data;
}
} catch {
logger.log(`Can't connect to the Docker API on ${host}`, 'ERROR');
}
if (containers) {
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 = [];
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]);
}
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'])
) {
const names = labels['flame.name'].split(';');
const urls = labels['flame.url'].split(';');
const categoriesLabels = labels['flame.category'] ? labels['flame.category'].split(';') : [];
const orders = labels['flame.order'] ? labels['flame.order'].split(';') : [];
const icons = labels['flame.icon'] ? labels['flame.icon'].split(';') : [];
for (let i = 0; i < names.length; i++) {
const category = categoriesLabels[i] ? categories.find(category => category.name.toUpperCase() === categoriesLabels[i].toUpperCase()) : dockerDefaultCategory;
if (!category) {
category = await createNewCategory(categoriesLabels[i]);
if (category) {
categories.push(category);
} else {
category = dockerDefaultCategory;
}
}
dockerApps.push({
name: names[i] || names[0],
url: urls[i] || urls[0],
icon: icons[i] || 'docker',
category: category.id,
orderId: orders[i] || 500,
});
}
}
}
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 {
// else create new app
await App.create({
...item,
icon: item.icon === 'custom' ? 'docker' : item.icon,
isPinned: true,
});
}
}
}
};
// TODO : Move somewhere else ?
async function createNewCategory(newCategoryName) {
return await Category.create({
name: newCategoryName,
type: 'apps',
isPinned: true,
orderId: Number.MAX_SAFE_INTEGER //New category will always be last and can then be re-ordered manually by user
});
}
module.exports = useDocker;

View file

@ -0,0 +1,115 @@
const App = require('../../../models/App');
const k8s = require('@kubernetes/client-node');
const Logger = require('../../../utils/Logger');
const logger = new Logger();
const loadConfig = require('../../../utils/loadConfig');
const kubernetesDefaultCategory = {
id: -3,
name: 'Kubernetes',
type: 'apps',
isPinned: true,
orderId: 999,
};
const useKubernetes = async (apps) => {
const { useOrdering: orderType, unpinStoppedApps } = await loadConfig();
let ingresses = null;
try {
const kc = new k8s.KubeConfig();
kc.loadFromCluster();
const k8sNetworkingV1Api = kc.makeApiClient(k8s.NetworkingV1Api);
await k8sNetworkingV1Api.listIngressForAllNamespaces().then((res) => {
ingresses = res.body.items;
});
} catch {
logger.log("Can't connect to the Kubernetes API", 'ERROR');
}
if (ingresses) {
apps = await App.findAll({
order: [[orderType, 'ASC']],
});
ingresses = ingresses.filter(
(e) => Object.keys(e.metadata.annotations).length !== 0
);
const kubernetesApps = [];
for (const ingress of ingresses) {
const annotations = ingress.metadata.annotations;
if (
'flame.pawelmalak/name' in annotations &&
'flame.pawelmalak/url' in annotations &&
/^app/.test(annotations['flame.pawelmalak/type'])
) {
const names = annotations['flame.pawelmalak/.name'].split(';');
const urls = annotations['flame.pawelmalak/url'].split(';');
const categoriesLabels = annotations['flame.pawelmalak/category'] ? annotations['flame.pawelmalak/category'].split(';') : [];
const orders = annotations['flame.pawelmalak/order'] ? annotations['flame.pawelmalak/order'].split(';') : [];
const icons = annotations['flame.pawelmalak/icon'] ? annotations['flame.pawelmalak/icon'].split(';') : [];
for (let i = 0; i < names.length; i++) {
const category = categoriesLabels[i] ? categories.find(category => category.name.toUpperCase() === categoriesLabels[i].toUpperCase()) : kubernetesDefaultCategory;
if (!category) {
category = await createNewCategory(categoriesLabels[i]);
if (category) {
categories.push(category);
} else {
category = kubernetesDefaultCategory;
}
}
kubernetesApps.push({
name: names[i] || names[0],
url: urls[i] || urls[0],
icon: icons[i] || 'kubernetes',
category: category.id,
orderId: orders[i] || 500,
});
}
kubernetesApps.push({
name: annotations['flame.pawelmalak/name'],
url: annotations['flame.pawelmalak/url'],
icon: annotations['flame.pawelmalak/icon'] || 'kubernetes',
});
}
}
if (unpinStoppedApps) {
for (const app of apps) {
await app.update({ isPinned: false });
}
}
for (const item of kubernetesApps) {
if (apps.some((app) => app.name === item.name)) {
const app = apps.find((a) => a.name === item.name);
await app.update({ ...item, isPinned: true });
} else {
await App.create({
...item,
isPinned: true,
});
}
}
}
};
// TODO : Move somewhere else ?
async function createNewCategory(newCategoryName) {
return await Category.create({
name: newCategoryName,
type: 'apps',
isPinned: true,
orderId: Number.MAX_SAFE_INTEGER //New category will always be last and can then be re-ordered manually by user
});
}
module.exports = useKubernetes;