Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Proxmox integration/widget #1903

Merged
merged 12 commits into from
Mar 23, 2024
157 changes: 130 additions & 27 deletions public/locales/en/modules/health-monitoring.json
Original file line number Diff line number Diff line change
@@ -1,38 +1,141 @@
{
"descriptor": {
"name": "System Health Monitoring",
"description": "Information about your NAS",
"settings": {
"title": "System Health Monitoring",
"fahrenheit": {
"label": "Fahrenheit"
}
}
},
"descriptor": {
"name": "System Health Monitoring",
"description": "Displays information showing the health and status of your system(s).",
"settings": {
"title": "Settings for system health monitoring",
"fahrenheit": {
"label": "CPU Temp in Fahrenheit"
},
"cpu": {
"label": "CPU",
"label": "Show CPU Info",
"load": "Load Average",
"minute": "{{minute}} minute",
"minutes": "{{minutes}} minutes"
},
"memory": {
"label": "Memory",
"totalMem": "Total memory: {{total}}GB",
"available": "Available: {{available}}GB - {{percentage}}%"
"label": "Show Memory Info"
},
"fileSystem": {
"label": "File System",
"available": "Available: {{available}} - {{percentage}}%"
},
"info": {
"uptime": "Uptime",
"updates": "Updates",
"reboot": "Reboot"
},
"errors": {
"general": {
"title": "Unable to find your NAS",
"text": "There was a problem connecting to your NAS. Please verify your configuration/integration(s)."
"label": "Show Filesystem Info"
},
"node": {
"label": "Filter by node name",
"info": "Enter your Proxmox node name to only show metrics for that node. By default, the entire cluster is shown."
},
"defaultViewState": {
"label": "Section open by default",
"data": {
"none": "None",
"node": "Nodes",
"vm": "VMs",
"lxc": "LXCs",
"storage": "Storage"
}
},
"defaultTabState": {
"label": "Tab open by default",
"info": "Tab open by default. Only used when multiple integrations are available.",
"data": {
"system": "System",
"cluster": "Cluster"
}
},
"summary": {
"label": "Show summary section"
},
"showNode": {
"label": "Show nodes section"
},
"showVM": {
"label": "Show VMs section"
},
"showLXCs": {
"label": "Show LXCs section"
},
"showStorage": {
"label": "Show storage section"
},
"sectionIndicatorColor": {
"label": "Requirement for section status indicator to be 'OK'",
"info": "'All' requires that all items be online for the indicator to be green. 'Any' requires at least one item to be online.",
"data": {
"any": "Any Active",
"all": "All Active"
}
},
"ignoreCert": {
"label": "Ignore Certificate Errors",
"info": "If enabled, the widget will ignore certificate errors when accessing the Proxmox API. This can be helpful when accessing Proxmox through HTTPS."
}
}
}
},
"cpu": {
"label": "CPU",
"load": "Load Average",
"minute": "{{minute}} minute"
},
"memory": {
"label": "Memory",
"totalMem": "Total memory: {{total}}GB",
"available": "Available: {{available}}GB - {{percentage}}%"
},
"fileSystem": {
"label": "File System",
"available": "Available: {{available}} - {{percentage}}%"
},
"info": {
"uptime": "Uptime",
"uptimeFormat": "{{days}} days, {{hours}} hours",
"updates": "Updates Available",
"reboot": "Reboot"
},
"errors": {
"general": {
"title": "Unable to find your system(s).",
"text": "There was a problem connecting to your system. Please verify your configuration/integration(s)."
}
},
"headings": {
"system": "System",
"cluster": "Cluster"
},
"cluster": {
"summary": {
"cpu": "CPU",
"ram": "RAM"
},
"accordion": {
"title": {
"nodes": "Nodes",
"vms": "VMs",
"lxcs": "LXCs",
"storage": "Storage"
}
},
"table": {
"header": {
"name": "Name",
"cpu": "CPU",
"ram": "RAM",
"node": "Node"
}
},
"popover": {
"node": "Node",
"vmid": "VMID",
"details": "Details",
"cores": "Cores - {{maxCpu}}",
"memSize": "Memory - {{maxMem}}",
"memRatio": "Memory - {{usedMem}} / {{maxMem}}",
"diskSize": "Disk - {{maxDisk}}",
"diskRatio": "Disk - {{usedDisk}} / {{maxDisk}}",
"uptime": "Uptime - {{uptime}}",
"plugin": "Plugin",
"ha": "HA State - {{haState}}",
"sharedStorage": "Shared Storage",
"localStorage": "Local Storage",
"na": "N/A"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,9 @@ export const availableIntegrations = [
image: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/openmediavault.png',
label: 'OpenMediaVault',
},
{
value: 'proxmox',
image: 'https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/proxmox.png',
label: 'Proxmox',
}
] as const satisfies Readonly<SelectItem[]>;
4 changes: 2 additions & 2 deletions src/server/api/root.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import { dashDotRouter } from './routers/dash-dot';
import { dnsHoleRouter } from './routers/dns-hole/router';
import { dockerRouter } from './routers/docker/router';
import { downloadRouter } from './routers/download';
import { healthMonitoringRouter } from './routers/health-monitoring/router';
import { iconRouter } from './routers/icon';
import { indexerManagerRouter } from './routers/indexer-manager';
import { inviteRouter } from './routers/invite/invite-router';
import { mediaRequestsRouter } from './routers/media-request';
import { mediaServerRouter } from './routers/media-server';
import { notebookRouter } from './routers/notebook';
import { openmediavaultRouter } from './routers/openmediavault';
import { overseerrRouter } from './routers/overseerr';
import { passwordRouter } from './routers/password';
import { rssRouter } from './routers/rss';
Expand Down Expand Up @@ -50,7 +50,7 @@ export const rootRouter = createTRPCRouter({
password: passwordRouter,
notebook: notebookRouter,
smartHomeEntityState: smartHomeEntityStateRouter,
openmediavault: openmediavaultRouter,
healthMonitoring: healthMonitoringRouter,
});

// export type definition of API
Expand Down
127 changes: 127 additions & 0 deletions src/server/api/routers/health-monitoring/openmediavault.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import axios from 'axios';
import Consola from 'consola';
import { checkIntegrationsType, findAppProperty } from '~/tools/client/app-properties';
import { getConfig } from '~/tools/config/getConfig';
import { ConfigAppType } from '~/types/app';

let sessionId: string | null = null;
let loginToken: string | null = null;

async function makeOpenMediaVaultRPCCall(
serviceName: string,
method: string,
params: Record<string, any>,
headers: Record<string, string>,
input: { configName: string }
) {
const config = getConfig(input.configName);
const app = config.apps.find((app) => checkIntegrationsType(app.integration, ['openmediavault']));

if (!app) {
Consola.error(`App 'openmediavault' not found for configName '${input.configName}'`);
return null;
}

const appUrl = new URL(app.url);
const response = await axios.post(
`${appUrl.origin}/rpc.php`,
{
service: serviceName,
method: method,
params: params,
},
{
headers: {
'Content-Type': 'application/json',
...headers,
},
}
);
return response;
}

export async function makeOpenMediaVaultCalls(app: ConfigAppType, input: any) {
let authResponse: any = null;

if (!sessionId || !loginToken) {
if (!app) {
Consola.error(
`Failed to process request to app 'openmediavault'. Please check username & password`
);
return null;
}

authResponse = await makeOpenMediaVaultRPCCall(
'session',
'login',
{
username: findAppProperty(app, 'username'),
password: findAppProperty(app, 'password'),
},
{},
input
);

if (authResponse.data.response.sessionid) {
sessionId = authResponse.data.response.sessionid;
} else {
const cookies = authResponse.headers['set-cookie'] || [];
sessionId = cookies
.find((cookie: any) => cookie.includes('X-OPENMEDIAVAULT-SESSIONID'))
?.split(';')[0];

loginToken = cookies
.find((cookie: any) => cookie.includes('X-OPENMEDIAVAULT-LOGIN'))
?.split(';')[0];
}

const responses = await Promise.allSettled([
makeOpenMediaVaultRPCCall(
'system',
'getInformation',
{},
loginToken
? { Cookie: `${loginToken};${sessionId}` }
: { 'X-OPENMEDIAVAULT-SESSIONID': sessionId as string },
input
),
makeOpenMediaVaultRPCCall(
'filesystemmgmt',
'enumerateMountedFilesystems',
{ includeroot: true },
loginToken
? { Cookie: `${loginToken};${sessionId}` }
: { 'X-OPENMEDIAVAULT-SESSIONID': sessionId as string },
input
),
makeOpenMediaVaultRPCCall(
'cputemp',
'get',
{},
loginToken
? { Cookie: `${loginToken};${sessionId}` }
: { 'X-OPENMEDIAVAULT-SESSIONID': sessionId as string },
input
),
]);

const systemInfoResponse =
responses[0].status === 'fulfilled' && responses[0].value
? responses[0].value.data?.response
: null;
const fileSystemResponse =
responses[1].status === 'fulfilled' && responses[1].value
? responses[1].value.data?.response
: null;
const cpuTempResponse =
responses[2].status === 'fulfilled' && responses[2].value
? responses[2].value.data?.response
: null;

return {
systemInfo: systemInfoResponse,
fileSystem: fileSystemResponse,
cpuTemp: cpuTempResponse,
};
}
}
Loading
Loading