diff --git a/.gitignore b/.gitignore index 67d0346..3751439 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ yarn-error.log* # production /build/ /data/ -/confs/ \ No newline at end of file +/confs/ +/private/ \ No newline at end of file diff --git a/components/layout.tsx b/components/layout.tsx index 6a2f966..9205de4 100644 --- a/components/layout.tsx +++ b/components/layout.tsx @@ -48,24 +48,6 @@ const Layout = ({ children }: { children: React.ReactNode }) => { defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "826fc083aa86417890c0ceb3e0a597fa"}'> -
diff --git a/interfaces/CardTypes.ts b/interfaces/CardTypes.ts index aabe411..bae386c 100644 --- a/interfaces/CardTypes.ts +++ b/interfaces/CardTypes.ts @@ -32,6 +32,7 @@ export enum Status { export enum ServiceLocation { brr7_4800u = "brr7-4800u", + tower_0 = "tower-0", other = "" } diff --git a/interfaces/DockerStatus.ts b/interfaces/DockerStatus.ts new file mode 100644 index 0000000..910f222 --- /dev/null +++ b/interfaces/DockerStatus.ts @@ -0,0 +1,11 @@ +import { ServiceLocation } from './CardTypes'; +export interface DockerInfo { + name: string, + status: DockerStatus, + id: string + location: ServiceLocation, +} + +export enum DockerStatus { + running = "running", +} diff --git a/pages/api/containers.tsx b/pages/api/containers.tsx index 6f75e6e..7f6a6d2 100644 --- a/pages/api/containers.tsx +++ b/pages/api/containers.tsx @@ -1,13 +1,29 @@ import Docker from 'dockerode' +import ApiSecret from '../../private/portainer_api_secret.json' +import { DockerInfo } from '../../interfaces/DockerStatus'; +import { ServiceLocation } from '../../interfaces/CardTypes'; export default async function ContainersAPI(req: any, res: any) { + const token = JSON.parse(JSON.stringify(ApiSecret.token)); + try { - const options = { - socketPath: '/var/run/docker.sock', - path: '/v1.41/containers/json' - }; - var docker = new Docker({ socketPath: options.socketPath }); - const list = await docker.listContainers({ all: true }) + const res1 = await fetch('https://portainer.neshweb.net/api/endpoints/2/docker/containers/json', { + method: "GET", + headers: {"X-API-Key": token} + }); + + const unparsed = await res1.json(); + let list: DockerInfo[] = []; + + unparsed.forEach((entry: any) => { + let newEntry = {} as DockerInfo; + + newEntry.name = entry.Names[0].substring(1); + newEntry.status = entry.State; + newEntry.id = entry.Id; + newEntry.location = ServiceLocation.tower_0; + list.push(newEntry); + }); res.status(200).json(list); } diff --git a/pages/servers.tsx b/pages/servers.tsx index 1acfe95..c193a49 100644 --- a/pages/servers.tsx +++ b/pages/servers.tsx @@ -1,7 +1,7 @@ import Head from 'next/head' import { Game } from '../interfaces/CardTypes'; import { PageContentBox, PageDescription, PageTitle, CardContentGame } from '../components/styles/content' -import GameList from '../public/pages.json'; +import GameList from '../public/data/pages.json'; function Servers() { // TODO: unuggly this shit diff --git a/pages/services.tsx b/pages/services.tsx index a42efab..fce23f6 100644 --- a/pages/services.tsx +++ b/pages/services.tsx @@ -5,6 +5,7 @@ import { ReactElement } from 'react' import useSWR from 'swr'; import { CardContentService, PageContentBox, PageDescription, PageTitle } from '../components/styles/content'; import ServiceList from '../public/data/pages.json'; +import { DockerInfo } from '../interfaces/DockerStatus'; const fetcher = (url: string) => fetch(url).then((res) => res.json()) @@ -56,82 +57,12 @@ function Services() { ) } -async function getStatus(entry: Service, containers: Dockerode.ContainerInfo[]) { +async function getStatus(entry: Service, containers: DockerInfo[]) { // Currently the only location supporting different fetching depending on type is brr7-4800u // Others to follow but low prio as this is currently the only location used - // Location BRR7-4800U - if (entry.location === ServiceLocation.brr7_4800u) { - // Type APP - if (entry.type === ServiceType.app) { - await fetch(entry.href) - .then((response) => { - if (response.ok) { - switch (response.status) { - case 200: - case 301: - case 302: - entry.status = Status.online; - break; - default: - entry.status = Status.offline; - } - } - else { - entry.status = Status.offline; - } - }) - .catch((error) => { - console.error("Error pinging Website: ", error); - entry.status = Status.error; - }) - } - // Type Docker - else if (entry.type === ServiceType.docker) { - if (entry.name !== null) { - let found = false; - for (let i = 0; i < containers.length; i++) { - const container = containers[i]; - // Docker API returns container names with / prepended - if (containers[i].Names.includes("/" + entry.docker_container_name)) { - // so far only "running" is properly implemented, mroe cases to follow as needed - switch (container.State) { - case "running": - entry.status = Status.online; - break; - default: - console.log("Container Status " + container.State + " has no case implemented"); - entry.status = Status.offline; - } - found = true; - // cancel the for - break; - } - // If container name is not missing the container is set to offline - else { - entry.status = Status.offline; - } - } - if (!found) { - console.warn("Container for " + entry.name + " could not be found"); - } - } - // if name is null do not enter for loop - else { - console.error("Container Name not specified"); - entry.status = Status.error; - } - } - // If no Type matches - else { - console.warn("Service Type for Service " + entry.name + " not specified or invalid"); - entry.status = Status.error; - } - } - // Location Other - // TODO: implement docker type for other locations - else if (entry.location === ServiceLocation.other) { - // Currently uses the same handling as app type for the other location + // Type APP + if (entry.type === ServiceType.app) { await fetch(entry.href) .then((response) => { if (response.ok) { @@ -154,15 +85,54 @@ async function getStatus(entry: Service, containers: Dockerode.ContainerInfo[]) entry.status = Status.error; }) } - // If no Location matches + // Type Docker + else if (entry.type === ServiceType.docker) { + if (entry.name !== null) { + let found = false; + for (let i = 0; i < containers.length; i++) { + const container = containers[i]; + // Docker API returns container names with / prepended + if (container.name === entry.docker_container_name) { + + if (container.location === entry.location) { + // so far only "running" is properly implemented, mroe cases to follow as needed + switch (container.status) { + case "running": + entry.status = Status.online; + break; + default: + console.log("Container Status " + container.status + " has no case implemented"); + entry.status = Status.offline; + } + found = true; + // cancel the for + break; + } + } + // If container name is not missing the container is set to offline + else { + entry.status = Status.offline; + } + } + if (!found) { + console.warn("Container for " + entry.name + " could not be found"); + } + } + // if name is null do not enter for loop + else { + console.error("Container Name not specified"); + entry.status = Status.error; + } + } + // If no Type matches else { - console.warn("Service Location for Service " + entry.name + " not specified"); + console.warn("Service Type for Service " + entry.name + " not specified or invalid"); entry.status = Status.error; } return entry; } -const fetchFullDataArray = (containerData: Dockerode.ContainerInfo[], dataSet: Service[]) => { +const fetchFullDataArray = (containerData: DockerInfo[], dataSet: Service[]) => { const fetchStatus = (entry: Service) => getStatus(entry, containerData); return Promise.all(dataSet.map(fetchStatus)); } diff --git a/public/data/pages.json b/public/data/pages.json index 57aff98..32e48a2 100644 --- a/public/data/pages.json +++ b/public/data/pages.json @@ -8,7 +8,7 @@ "warn": "Note: Registration requires approval", "type": "docker", "docker_container_name": "nextcloud", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Kavita", @@ -18,17 +18,7 @@ "warn": "Registration via Admin invite", "type": "docker", "docker_container_name": "kavita", - "location": "brr7-4800u" - }, - { - "name": "Komga", - "icon": "/icons/komga-logo.png", - "href": "https://komga.neshweb.net", - "desc": "Self-hosted Comic Library", - "warn": "Note: Registration only via Admin", - "type": "docker", - "docker_container_name": "komga", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Calibre Web", @@ -36,8 +26,9 @@ "href": "https://calibre.neshweb.net/", "desc": "Self-hosted Ebook Library Service", "warn": "Note: Registration only via Admin", - "type": "app", - "location": "brr7-4800u" + "type": "docker", + "docker_container_name": "calibre-web", + "location": "tower-0" }, { "name": "PeerTube", @@ -47,7 +38,7 @@ "warn": "Note: Registration only via Admin", "type": "docker", "docker_container_name": "peertube", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Mastodon", @@ -57,7 +48,7 @@ "warn": "Note: Registration requires approval", "type": "docker", "docker_container_name": "mastodon-web", - "location": "brr7-4800u" + "location": "tower-0" }, { @@ -68,7 +59,7 @@ "warn": "Note: Invite only", "type": "docker", "docker_container_name": "vaultwarden", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "File Browser", @@ -77,7 +68,7 @@ "warn": "Note: Registration only via Admin", "type": "docker", "docker_container_name": "filebrowser", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Jellyfin", @@ -87,7 +78,7 @@ "warn": "Note: Registration only via Admin", "type": "docker", "docker_container_name": "jellyfin", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Navidrome", @@ -97,7 +88,7 @@ "warn": "Note: Registration only via Admin", "type": "docker", "docker_container_name": "navidrome", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Picard", @@ -106,7 +97,7 @@ "warn": "Note: Access only via Admin", "type": "docker", "docker_container_name": "picard", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Gitlab", @@ -116,7 +107,7 @@ "warn": "Note: Registration only via Admin", "type": "docker", "docker_container_name": "gitlab", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Portainer", @@ -126,7 +117,7 @@ "warn": "Note: Admin Only", "type": "docker", "docker_container_name": "portainer", - "location": "brr7-4800u" + "location": "tower-0" }, { "name": "Nginx Proxy Manager", @@ -136,26 +127,16 @@ "warn": "Note: Admin Only", "type": "docker", "docker_container_name": "nginx-prox", - "location": "brr7-4800u" + "location": "tower-0" }, { - "name": "Grafana", - "icon": "/icons/grafana-logo.svg", - "href": "https://monitoring.neshweb.net/", - "desc": "Server Monitoring Utility", + "name": "Proxmox", + "icon": "/icons/proxmox-logo.png", + "href": "https://proxmox.neshweb.net/", + "desc": "Hypervisor Webinterface", "warn": "Note: Admin Only", - "type": "docker", - "docker_container_name": "grafana", - "location": "brr7-4800u" - }, - { - "name": "Matomo", - "href": "https://tracking.neshweb.net/", - "desc": "Traffic Tracking Utility", - "warn": "Note: Admin Only", - "type": "docker", - "docker_container_name": "matomo-web", - "location": "brr7-4800u" + "type": "app", + "location": "" } ], "games": { diff --git a/public/pages.json b/public/pages.json deleted file mode 100644 index f7378c9..0000000 --- a/public/pages.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "services": [ - { - "name": "Nextcloud", - "icon": "/icons/nextcloud-logo.svg", - "href": "https://nextcloud.neshweb.net/", - "desc": "Self-hosted Cloud Storage Service", - "warn": "Note: Registration requires approval", - "type": "docker", - "docker_container_name": "nextcloud", - "location": "brr7-4800u" - }, - { - "name": "Komga", - "icon": "/icons/komga-logo.png", - "href": "https://komga.neshweb.net/", - "desc": "Self-hosted Comic Library", - "warn": "Note: Registration only via Admin", - "type": "docker", - "docker_container_name": "komga", - "location": "brr7-4800u" - }, - { - "name": "Calibre Web", - "icon": "/icons/calibre-logo.ico", - "href": "https://calibre.neshweb.net/", - "desc": "Self-hosted Ebook Library Service", - "warn": "Note: Registration only via Admin", - "type": "app", - "location": "brr7-4800u" - }, - { - "name": "PeerTube", - "icon": "/icons/peertube-logo.svg", - "href": "https://tube.neshweb.net/", - "desc": "Self-hosted PeerTube Instance", - "warn": "Note: Registration only via Admin", - "type": "docker", - "docker_container_name": "peertube", - "location": "brr7-4800u" - }, - { - "name": "Mastodon", - "icon": "/icons/mastodon-logo.svg", - "href": "https://mastodon.neshweb.net/", - "desc": "Self-hosted Mastodon Instance", - "warn": "Note: Registration requires approval", - "type": "docker", - "docker_container_name": "mastodon-web", - "location": "brr7-4800u" - }, - { - "name": "File Browser", - "href": "https://files.neshweb.net/", - "desc": "Server File Browser", - "warn": "Note: Registration only via Admin", - "type": "docker", - "docker_container_name": "filebrowser", - "location": "brr7-4800u" - }, - { - "name": "Jellyfin", - "icon": "/icons/jellyfin-logo.svg", - "href": "https://jellyfin.neshweb.net/", - "desc": "Open-Source, Self-Hosted Media Platform", - "warn": "Note: Registration only via Admin", - "type": "docker", - "docker_container_name": "jellyfin", - "location": "brr7-4800u" - }, - { - "name": "Navidrome", - "icon": "/icons/navidrome-logo.png", - "href": "https://navidrome.neshweb.net/", - "desc": "Open-Source, Self-Hosted Music Streaming Platform", - "warn": "Note: Registration only via Admin", - "type": "docker", - "docker_container_name": "navidrome", - "location": "brr7-4800u" - }, - { - "name": "Picard", - "href": "https://picard.neshweb.net/", - "desc": "MP3 Tagger", - "warn": "Note: Access only via Admin", - "type": "docker", - "docker_container_name": "picard", - "location": "brr7-4800u" - }, - { - "name": "Gitlab", - "icon": "/icons/gitlab-logo.svg", - "href": "https://gitlab.neshweb.net/", - "desc": "Self-hosted Git Service", - "warn": "Note: Registration only via Admin", - "type": "docker", - "docker_container_name": "gitlab", - "location": "brr7-4800u" - }, - { - "name": "Portainer", - "icon": "/icons/portainer-logo.png", - "href": "https://portainer.neshweb.net/", - "desc": "Docker Container Manager", - "warn": "Note: Admin Only", - "type": "docker", - "docker_container_name": "portainer", - "location": "brr7-4800u" - }, - { - "name": "Nginx Proxy Manager", - "icon": "/icons/npm-logo.png", - "href": "https://nginx.neshweb.net/", - "desc": "Web-based Nginx Proxy Manager", - "warn": "Note: Admin Only", - "type": "docker", - "docker_container_name": "nginx-prox", - "location": "brr7-4800u" - }, - { - "name": "Grafana", - "icon": "/icons/grafana-logo.svg", - "href": "https://monitoring.neshweb.net/", - "desc": "Server Monitoring Utility", - "warn": "Note: Admin Only", - "type": "docker", - "docker_container_name": "grafana", - "location": "brr7-4800u" - }, - { - "name": "Matomo", - "href": "https://tracking.neshweb.net/", - "desc": "Traffic Tracking Utility", - "warn": "Note: Admin Only", - "type": "docker", - "docker_container_name": "matomo-web", - "location": "brr7-4800u" - } - ], - "games": { - "minecraft": { - "name": "Minecraft", - "icon": "/icons/minecraft-logo.png", - "href": "https://minecraft.neshweb.net/", - "desc": "View all currently available Minecraft Servers and their mods" - }, - "ready_or_not": { - "name": "Ready or Not", - "icon": "/icons/ron-logo.png", - "href": "https://readyornot.neshweb.net/", - "desc": "Collection of Floor Plans for the Game 'Ready or Not'" - }, - "zomboid": { - "name": "Zomboid", - "icon": "/icons/zomboid-logo.png", - "ip": "91.13.248.30", - "status": "Online" - } - } -}