glance icon indicating copy to clipboard operation
glance copied to clipboard

Looking to implement Proxmox monitoring

Open KevinFumbles opened this issue 9 months ago • 10 comments

Description

I use Proxmox to host Glance among other VMs/LXCs and I'm looking to implement a widget that display stats from Proxmox similar to Server Stats but with a little more info specific to Proxmox (e.g. nodes status, guests running/stopped, updates available).

I'm curious to know if this should be a built-in widget added via PR or an extension hosted on my Github profile, but still available for anyone to use

KevinFumbles avatar Feb 14 '25 09:02 KevinFumbles

Hey, in order to prevent Glance from becoming too bloated with features that may not be used by many, I'd suggest giving it a while to see if anyone else would be interested in this. Also, I personally don't use Proxmox so I wouldn't be able to test or maintain this should the need arise.

In the meantime, if this can be done via a single request to a JSON API, I'd suggest implementing it with the custom-api widget which would make it much simpler to share with others compared to an extension widget.

svilenmarkov avatar Feb 15 '25 15:02 svilenmarkov

Makes sense! Yeah I’ll see if I can make this work through the custom API widget, and share my results here.

KevinFumbles avatar Feb 15 '25 16:02 KevinFumbles

@svilenmarkov the data output by the proxmox API endpoint /api2/json/cluster/resources has an array list of all services together (qemu, lxc, storage and node itself), is there a way to manipulate the data first before passing them trough the template? something like:

const vmList = data.filter(d => d.type === 'qemu'); // for VMs
const lxcList = data.filter(d => d.type === 'lxc'); // for LXC

since the type: node only shows the server specs

EDIT: There is a parameter of ?type=node but that will not show the number of VMs or LXCs

ralphocdol avatar Feb 18 '25 13:02 ralphocdol

@ralphocdol What you could do is {{ continue }} if the type doesn't equal what you expect:

{{ range .JSON.Array "list" }}
  {{ if ne "qemu" .String "type" }}{{ continue }}{{ end }}
  <div>{{ .String "type" }}</div> <!-- this will always show "qemu" -->
{{ end }}

svilenmarkov avatar Feb 22 '25 17:02 svilenmarkov

@svilenmarkov sorry, what I had in mind was to know how many VMs/LXC my proxmox have and how many were active hence the script to manipulate the data first so it can be possible to create a new JSON output. What I did now was I made an API as a middleman to call the Proxmox API and generate a new JSON output which will then be used for custom-api widget.

ralphocdol avatar Feb 22 '25 18:02 ralphocdol

@svilenmarkov sorry, what I had in mind was to know how many VMs/LXC my proxmox have and how many were active hence the script to manipulate the data first so it can be possible to create a new JSON output. What I did now was I made an API as a middleman to call the Proxmox API and generate a new JSON output which will then be used for custom-api widget.

Can you share how? Plus I want almost the same but for Scrutiny and WUD *what's up docker) but I have no idea how to do so..

For WUD I tried:

- type: custom-api
          title: Whats Up Docker
          #cache: 5m
          url: http://192.168.15.3:3001/api/containers
          headers:
            Accept: application/json
          template: |
            <div class="flex justify-between text-center">
              <div>
                <div class="color-highlight size-h3">{{ .JSON.Int "updateAvailable" | formatNumber }}</div>
                <div class="size-h6">UPDATES</div>
              </div>
              <div>
                <div class="color-highlight size-h3">{{ .JSON.Int "updates.outdated" | formatNumber }}</div>
                <div class="size-h6">OUTDATED</div>
              </div>
              <div>
                <div class="color-highlight size-h3">{{ .JSON.Int "totalContainers" | formatNumber }}</div>
                <div class="size-h6">TOTAL</div>
              </div>
            </div> 

But it only show the columns with 0 for everything.

brkr1 avatar Mar 09 '25 00:03 brkr1

@brkr1 looking at the API for WUD, you'd definitely need some sort of middleware to count those results Using nodejs webserver with express:

const getWudData = async (req, res) => {
    try {
        const response = await fetch(`http://192.168.15.3:3001/api/containers`, {
            headers: {
                'Content-Type': 'application/json',
            },
        });
        const data = await response.json();
        const updatesAvailable = data.filter(d => d.updateAvailable).length || 0;
        // Not sure how you get the outdated as I don't see it in their documentation, 
        // and by the sounds of it, it's the same as updatesAvailable
        const totalContainers = data.length || 0;
        res.json({
            updatesAvailable,
            totalContainers,
        });
    } catch (error) {
        console.log({error})
        res.status(500).send('Something went wrong');
    }
}

ralphocdol avatar Mar 09 '25 04:03 ralphocdol

@brkr1 looking at the API for WUD, you'd definitely need some sort of middleware to count those results Using nodejs webserver with express:

const getWudData = async (req, res) => { try { const response = await fetch(http://192.168.15.3:3001/api/containers, { headers: { 'Content-Type': 'application/json', }, }); const data = await response.json(); const updatesAvailable = data.filter(d => d.updateAvailable).length || 0; // Not sure how you get the outdated as I don't see it in their documentation, // and by the sounds of it, it's the same as updatesAvailable const totalContainers = data.length || 0; res.json({ updatesAvailable, totalContainers, }); } catch (error) { console.log({error}) res.status(500).send('Something went wrong'); } }

It worked. Thank you so much!

I'll leave it here in case others want that too

const express = require('express');
const fetch = require('node-fetch');
const app = express();
const PORT = 3005;

app.get('/wud-summary', async (req, res) => {
    try {
        const response = await fetch('http://192.168.15.3:3001/api/containers', {
            headers: { 'Content-Type': 'application/json' },
        });
        const data = await response.json();
        
        const updatesAvailable = data.filter(d => d.updateAvailable).length || 0;
        const totalContainers = data.length || 0;
        
        res.json({ updatesAvailable, totalContainers });
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: 'Failed to fetch data' });
    }
});

app.listen(PORT, () => {
    console.log(`Server running on http://192.168.15.3:${PORT}`);
});

Glance api-custom

- type: custom-api
          title: Whats Up Docker
          url: http://192.168.15.3:3005/wud-summary
          headers:
          Accept: application/json
          template: |
            <div class="flex justify-between text-center">
              <div class="flex-1">
                <a href="http://192.168.15.3:3001" target="_blank" class="color-highlight size-h3">
                 <div class="color-highlight size-h3">{{ .JSON.Int "updatesAvailable" | formatNumber }}</div>
                </a>
                 <div class="size-h6">UPDATES</div>
              </div>
              <div class="flex-1">
                <div class="color-highlight size-h3">{{ .JSON.Int "totalContainers" | formatNumber }}</div>
                <div class="size-h6">TOTAL</div>
              </div>
            </div>

brkr1 avatar Mar 11 '25 14:03 brkr1

Hello everyone, since this request is in backlog I'd like to share my interest as well, possibly for a widget like the server stats, but with added the number of VMs or CTs active on the system.

Thanks a lot for this beautiful piece of software!!

danixland avatar Mar 14 '25 10:03 danixland

There's a PR for this now #412

ralphocdol avatar Mar 17 '25 01:03 ralphocdol