浏览代码

MHO/Docker Swarm

feat: add docker swarm services
Matthew Horwood 3 年之前
父节点
当前提交
b60bd3120b
共有 1 个文件被更改,包括 129 次插入62 次删除
  1. 129 62
      controllers/apps/docker/useDocker.js

+ 129 - 62
controllers/apps/docker/useDocker.js

@@ -11,20 +11,62 @@ const useDocker = async (apps) => {
     dockerHost: host,
     dockerHost: host,
   } = await loadConfig();
   } = await loadConfig();
 
 
+  const dockerApps = [];
+
   let containers = null;
   let containers = null;
+  let containers_swarm = null;
+
+  function addApp(dockerApps, labels){
+    // 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',
+        });
+      }
+    }
+  }
 
 
   // Get list of containers
   // Get list of containers
   try {
   try {
     if (host.includes('localhost')) {
     if (host.includes('localhost')) {
       // Use default host
       // Use default host
-      let { data } = await axios.get(
-        `http://${host}/containers/json?{"status":["running"]}`,
-        {
-          socketPath: '/var/run/docker.sock',
-        }
-      );
+      function getDocker(){
+        return axios.get(
+          `http://${host}/containers/json?{"status":["running"]}`,
+          {
+            socketPath: '/var/run/docker.sock',
+          }
+        );
+      }
+      function getSwarm(){
+        return axios.get(
+          `http://${host}/services`,
+          {
+            socketPath: '/var/run/docker.sock',
+          }
+        );
+      }
+
+      [ containers, containers_swarm ] = await Promise.all(
+        [getDocker(),
+          getSwarm()
+        ]);
 
 
-      containers = data;
     } else {
     } else {
       // Use custom host
       // Use custom host
       let { data } = await axios.get(
       let { data } = await axios.get(
@@ -37,20 +79,17 @@ const useDocker = async (apps) => {
     logger.log(`Can't connect to the Docker API on ${host}`, 'ERROR');
     logger.log(`Can't connect to the Docker API on ${host}`, 'ERROR');
   }
   }
 
 
-  if (containers) {
+  if (containers_swarm) {
     apps = await App.findAll({
     apps = await App.findAll({
       order: [[orderType, 'ASC']],
       order: [[orderType, 'ASC']],
     });
     });
 
 
-    // Filter out containers without any annotations
-    containers = containers.filter((e) => Object.keys(e.Labels).length !== 0);
+    services = containers_swarm.data;
+    for (const service of services) {
+      let labels = service.Spec.Labels;
 
 
-    const dockerApps = [];
-
-    for (const container of containers) {
-      let labels = container.Labels;
-
-      // Traefik labels for URL configuration
+      labels['flame.name'] = service.Spec.Name;
+      labels['flame.type'] = 'application';
       if (!('flame.url' in labels)) {
       if (!('flame.url' in labels)) {
         for (const label of Object.keys(labels)) {
         for (const label of Object.keys(labels)) {
           if (/^traefik.*.frontend.rule/.test(label)) {
           if (/^traefik.*.frontend.rule/.test(label)) {
@@ -81,68 +120,96 @@ const useDocker = async (apps) => {
           }
           }
         }
         }
       }
       }
+      addApp(dockerApps, labels);
+    }
+  }
 
 
-      // 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 (containers) {
+    apps = await App.findAll({
+      order: [[orderType, 'ASC']],
+    });
 
 
-          if ('flame.icon' in labels) {
-            icons = labels['flame.icon'].split(';');
-          }
+    // Filter out containers without any annotations
+    containers = containers.data.filter((e) => Object.keys(e.Labels).length !== 0);
+
+    for (const container of containers) {
+      let labels = container.Labels;
+      if(!('com.docker.stack.namespace' in labels)){
+        console.log(container)
+        labels['flame.name'] = container.Names[0];
+        labels['flame.type'] = 'application';
+      // 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]);
+                }
 
 
-          dockerApps.push({
-            name: names[i] || names[0],
-            url: urls[i] || urls[0],
-            icon: icons[i] || 'docker',
-          });
+                if (domains.length > 0) {
+                  labels['flame.url'] = domains.join(';');
+                }
+              }
+            }
+          }
         }
         }
       }
       }
+      addApp(dockerApps, labels);
     }
     }
+  }
 
 
-    if (unpinStoppedApps) {
-      for (const app of apps) {
-        await app.update({ isPinned: false });
-      }
+  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);
 
 
-    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,
-          });
-        }
+      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 {
       } else {
-        // else create new app
-        await App.create({
+        await app.update({
           ...item,
           ...item,
-          icon: item.icon === 'custom' ? 'docker' : item.icon,
           isPinned: true,
           isPinned: true,
         });
         });
       }
       }
+    } else {
+      // else create new app
+      await App.create({
+        ...item,
+        icon: item.icon === 'custom' ? 'docker' : item.icon,
+        isPinned: true,
+      });
     }
     }
   }
   }
+
 };
 };
 
 
 module.exports = useDocker;
 module.exports = useDocker;