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

feat: add proxmox integration #1752

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IconKey, IconPassword, IconUser } from "@tabler/icons-react";
import { IconGrid3x3, IconKey, IconPassword, IconServer, IconUser } from "@tabler/icons-react";

import type { IntegrationSecretKind } from "@homarr/definitions";
import type { TablerIcon } from "@homarr/ui";
Expand All @@ -7,4 +7,6 @@ export const integrationSecretIcons = {
username: IconUser,
apiKey: IconKey,
password: IconPassword,
realm: IconServer,
tokenId: IconGrid3x3
} satisfies Record<IntegrationSecretKind, TablerIcon>;
8 changes: 8 additions & 0 deletions packages/definitions/src/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export const integrationSecretKindObject = {
apiKey: { isPublic: false },
username: { isPublic: true },
password: { isPublic: false },
tokenId: { isPublic: true },
realm: { isPublic: true }
} satisfies Record<string, { isPublic: boolean }>;

export const integrationSecretKinds = objectKeys(integrationSecretKindObject);
Expand Down Expand Up @@ -137,6 +139,12 @@ export const integrationDefs = {
category: ["mediaTranscoding"],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/tdarr.png",
},
proxmox: {
name: "Proxmox",
secretKinds: [['username', 'tokenId', 'apiKey', 'realm']],
category: ['healthMonitoring'],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/proxmox.png"
}
} as const satisfies Record<string, integrationDefinition>;

export const integrationKinds = objectKeys(integrationDefs) as AtLeastOneOf<IntegrationKind>;
Expand Down
1 change: 1 addition & 0 deletions packages/integrations/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@homarr/translation": "workspace:^0.1.0",
"@homarr/validation": "workspace:^0.1.0",
"@jellyfin/sdk": "^0.11.0",
"proxmox-api": "^1.1.1",
"xml2js": "^0.6.2"
},
"devDependencies": {
Expand Down
2 changes: 2 additions & 0 deletions packages/integrations/src/base/creator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { PiHoleIntegration } from "../pi-hole/pi-hole-integration";
import { PlexIntegration } from "../plex/plex-integration";
import { ProwlarrIntegration } from "../prowlarr/prowlarr-integration";
import type { Integration, IntegrationInput } from "./integration";
import { ProxmoxIntegration } from "../proxmox/proxmox-integration";

export const integrationCreator = <TKind extends keyof typeof integrationCreators>(
integration: IntegrationInput & { kind: TKind },
Expand Down Expand Up @@ -72,4 +73,5 @@ export const integrationCreators = {
readarr: ReadarrIntegration,
dashDot: DashDotIntegration,
tdarr: TdarrIntegration,
proxmox: ProxmoxIntegration
} satisfies Record<IntegrationKind, new (integration: IntegrationInput) => Integration>;
1 change: 1 addition & 0 deletions packages/integrations/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export { PlexIntegration } from "./plex/plex-integration";
export { ProwlarrIntegration } from "./prowlarr/prowlarr-integration";
export { LidarrIntegration } from "./media-organizer/lidarr/lidarr-integration";
export { ReadarrIntegration } from "./media-organizer/readarr/readarr-integration";
export { ProxmoxIntegration } from "./proxmox/proxmox-integration";

// Types
export type { IntegrationInput } from "./base/integration";
Expand Down
69 changes: 69 additions & 0 deletions packages/integrations/src/proxmox/proxmox-integration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import proxmoxApi from "proxmox-api";

import { Integration } from "../base/integration";
import type { HealthMonitoring } from "../interfaces/health-monitoring/healt-monitoring";

export class ProxmoxIntegration extends Integration {
public async testConnectionAsync(): Promise<void> {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; // TODO: Can we improve this?

Check failure

Code scanning / CodeQL

Disabling certificate validation High

Disabling certificate validation is strongly discouraged.

Copilot Autofix AI 27 days ago

To fix the problem, we need to ensure that TLS certificate validation is not disabled. Instead of setting process.env.NODE_TLS_REJECT_UNAUTHORIZED to "0", we should allow the default behavior of Node.js to validate certificates. If there is a need to handle self-signed certificates or certificates from a private CA, we should configure the application to trust those certificates explicitly.

The best way to fix this without changing existing functionality is to remove the line that sets process.env.NODE_TLS_REJECT_UNAUTHORIZED to "0". If necessary, we can add logic to handle custom certificates securely.

Suggested changeset 1
packages/integrations/src/proxmox/proxmox-integration.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/integrations/src/proxmox/proxmox-integration.ts b/packages/integrations/src/proxmox/proxmox-integration.ts
--- a/packages/integrations/src/proxmox/proxmox-integration.ts
+++ b/packages/integrations/src/proxmox/proxmox-integration.ts
@@ -7,3 +7,2 @@
   public async testConnectionAsync(): Promise<void> {
-    process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; // TODO: Can we improve this?
     const proxmox = this.getPromoxApi();
EOF
@@ -7,3 +7,2 @@
public async testConnectionAsync(): Promise<void> {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; // TODO: Can we improve this?
const proxmox = this.getPromoxApi();
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
const proxmox = this.getPromoxApi();
await proxmox.nodes.$get();
}

public async getSystemInfoAsync(): Promise<HealthMonitoring> {
const proxmox = this.getPromoxApi();
const resources = await proxmox.cluster.resources.$get();

let resourceSummary: ResourceSummary = { vms: [], lxcs: [], nodes: [], storage: [] };

Check failure on line 17 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

'resourceSummary' is never reassigned. Use 'const' instead
resources.forEach((item) => {
let resource: ResourceData = {

Check failure on line 19 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

'resource' is never reassigned. Use 'const' instead
id: item.id,
cpu: item.cpu ? item.cpu : 0,
maxCpu: item.maxcpu ? item.maxcpu : 0,
maxMem: item.maxmem ? item.maxmem : 0,
mem: item.mem ? item.mem : 0,
name: item.name,
node: item.node,
status: item.status,
running: false,
type: item.type,
uptime: item.uptime,
vmId: item.vmid,
netIn: item.netin,

Check failure on line 32 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value
netOut: item.netout,

Check failure on line 33 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value
diskRead: item.diskread,

Check failure on line 34 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value
diskWrite: item.diskwrite,

Check failure on line 35 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe assignment of an `any` value
disk: item.disk,
maxDisk: item.maxdisk,
haState: item.hastate,
storagePlugin: item.plugintype,
storageShared: item.shared == 1,
};
if (item.template == 0) {
if (item.type === "qemu") {
resource.running = resource.status === "running";

Check failure on line 44 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .running on an `error` typed value

Check failure on line 44 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .status on an `error` typed value
resourceSummary.vms.push(resource);

Check failure on line 45 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe call of a(n) `error` type typed value

Check failure on line 45 in packages/integrations/src/proxmox/proxmox-integration.ts

View workflow job for this annotation

GitHub Actions / lint

Unsafe member access .vms on an `error` typed value
} else if (item.type === "lxc") {
resource.running = resource.status === "running";
resourceSummary.lxcs.push(resource);
}
} else if (item.type === "node") {
resource.name = item.node;
resource.running = resource.status === "online";
resourceSummary.nodes.push(resource);
} else if (item.type === "storage") {
resource.name = item.storage;
resource.running = resource.status === "available";
resourceSummary.storage.push(resource);
}
});
}

private getPromoxApi() {
return proxmoxApi({
host: this.url("/").host,
tokenID: `${this.getSecretValue("username")}@${this.getSecretValue("realm")}!${this.getSecretValue("tokenId")}`,
tokenSecret: this.getSecretValue("apiKey"),
});
}
}
8 changes: 8 additions & 0 deletions packages/translation/src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,14 @@
"password": {
"label": "Password",
"newLabel": "New password"
},
"tokenId": {
"label": "Token ID",
"newLabel": "New token ID"
},
"realm": {
"label": "Realm",
"newLabel": "New realm"
}
}
},
Expand Down
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading