Most teams I work with already have a Grafana that the operations people open every morning, with a Prometheus behind it. When HPE Morpheus Enterprise or HPE VM Essentials arrives, the state of the clusters, hosts and virtual machines lives in the Morpheus UI, which is one more screen to check. This article puts that information on the Grafana you already have.
This is what you end up with:
What the dashboards watch
| Dashboard | Reads from | What it watches | The question it answers |
|---|---|---|---|
| Morpheus Overview | Morpheus API | Counts of apps, hosts and VMs, clusters and clouds; cluster list; per-cluster CPU and memory; datastore used space; appliance CPU, memory, storage and services; monitoring checks and incidents; recent activity; one VM table per cloud | Is the platform healthy, and what is running where? |
| VM Essentials Overview | VM Essentials API | The same as Morpheus Overview, without apps and monitoring | Is the platform healthy, and what is running where? |
| HVM Hosts and VMs | Prometheus | Host CPU, memory, load per core, running VMs, disk IOPS and latency, network; per VM state, vCPU, CPU %, memory, IOPS and traffic; top 10 VMs | How busy is each host, and which VMs use it most? |
| HVM Bottlenecks | Prometheus | CPU, memory and I/O pressure (PSI), vCPU wait, swap and page faults, disk busy time and latency, noisy neighbours, interface drops and errors | Why is a host or VM slow, and which resource is short? |
| HVM Capacity | Prometheus | vCPU to core ratio, allocated memory against host memory, idle cores, available memory, 30-day trends of CPU, memory and running VMs | How much room is left, and how fast is it being used? |
| Kubernetes Pods (optional) | Prometheus inside the HKS cluster | Node CPU and memory; per pod CPU, memory, network and PVC usage | Which pods use the cluster's resources? |
Before you start
I assume Prometheus and Grafana are already installed and working, and that you can edit the Prometheus configuration and add data sources in Grafana. The article does not cover installing either of them. It covers everything needed to connect Morpheus Enterprise and VM Essentials to them.
A few terms
| Term | What it means here |
|---|---|
| HVM host | A physical server that runs virtual machines with KVM. Both Morpheus Enterprise and VM Essentials use these hosts. |
| VM Essentials manager | The management appliance of VM Essentials. It has the same REST API as Morpheus Enterprise, with fewer features. |
| Exporter | A small service that publishes metrics on an HTTP port, for example http://host:9100/metrics. |
| Scrape | Prometheus reading an exporter's metrics at a fixed interval and storing them. |
| Data source | A connection in Grafana. Every dashboard panel reads from one. |
| Infinity | A Grafana data source plugin that reads JSON from any REST API. We use it to read the Morpheus API. |
How the pieces fit
There are two paths into Grafana, and each one does a different job:
| Path | What Grafana shows | How often it changes |
|---|---|---|
| Grafana, Infinity plugin, Morpheus API | Clusters, hosts and VMs, datastores, appliance health, recent activity | Every refresh, no history |
| Grafana, Prometheus, exporters on the HVM hosts | Host and VM CPU, memory, disk, network, bottlenecks, capacity | Every scrape, with history |
The two exporters run on each HVM host:
-
node_exporterpublishes host metrics (CPU, memory, disks, network, pressure) on port 9100. -
prometheus-libvirt-exporterpublishes one set of metrics per virtual machine on port 9177. It reads libvirt, the service that runs the VMs on the host.
The virtual machine name in these metrics is the same name Morpheus shows, so you can go from a dashboard straight to the VM in the Morpheus UI.
Which part you need
The steps are split into two parts, one per product. Each part is complete on its own, so follow only the one that matches your environment.
| Your environment | Follow |
|---|---|
| Morpheus Enterprise, with its HVM clusters | Part 1 |
| VM Essentials only | Part 2 |
What I tested with
- Morpheus Enterprise 9.0.2 and a VM Essentials manager, HVM hosts on Ubuntu 24.04 with libvirt 10.0
- Grafana 13.2 with the Infinity plugin 4.0
- Prometheus 3.5
- node_exporter 1.7.0 (the Ubuntu package) and prometheus-libvirt-exporter 2.6.0
Older versions of Grafana and Prometheus should work as well, but I have not checked them.
The source label
The HVM dashboards only show metrics that carry a label named source. You add this label in the Prometheus jobs of the HVM hosts, with one value per environment, for example enterprise or vme. An Environment menu at the top of each HVM dashboard then picks the value.
This keeps other servers that your Prometheus already scrapes with node_exporter off these dashboards.
Part 1: Morpheus Enterprise
Steps 1.1 to 1.3 are done in the Morpheus UI as an administrator, step 1.4 on each HVM host, step 1.5 on the Prometheus server and steps 1.6 to 1.9 in Grafana.
1.1 Create a read-only role
Grafana reads Morpheus through one API user, so the role behind that user decides what Grafana can see. Start from an empty role instead of copying one, because a copy tends to bring permissions nobody remembers to remove.
Go to Administration > Roles, click + Add and create a User Role named Grafana Reader. Leave the two multitenant boxes unticked.
Open the new role. Every entry starts with Access set to None. Set only these entries to Read:
| Section | Name | Access |
|---|---|---|
| Operations | Activity | Read |
| Operations | Guidance | Read |
| Provisioning | Apps | Read |
| Infrastructure | Clouds | Read |
| Infrastructure | Clusters | Read |
| Infrastructure | Compute | Read |
| Infrastructure | Storage | Read |
| Admin | Health | Read |
| Monitoring | Monitoring | Read |
On the Groups tab, set the groups you want to see on the dashboards to Read.
1.2 Create the service user
Go to Administration > Users > + Add and create:
- Username:
grafana-reader - Name and email: anything that tells your colleagues what the account is for
- Roles:
Grafana Readeronly - Password: a long one that meets your password policy
Keep the password in a safe place. You need it again when you renew the token.
1.3 Get an API token
Grafana logs in to the API with a token, not with the password. A token issued through the default morph-api client is valid for 30 days. To avoid renewing it every month, create a separate client with a longer lifetime and use it only for this account.
Go to Administration > Settings > Clients and click + Add Client:
- Client ID:
grafana - Access Token Validity Interval (seconds):
31536000, which is one year - Refresh Token Validity Interval (seconds):
31536000 - Client Secret and Redirect URL: leave empty
Pick a shorter lifetime if your security team prefers it. The only cost is renewing more often.
Now request the token. Run this from any machine that reaches Morpheus:
MORPHEUS=https://morpheus.example.com
curl -sk -X POST "$MORPHEUS/oauth/token" \
--data-urlencode grant_type=password \
--data-urlencode scope=write \
--data-urlencode client_id=grafana \
--data-urlencode username=grafana-reader \
--data-urlencode 'password=YOUR_PASSWORD'
The answer contains access_token and expires_in. expires_in should be close to 31536000. If it is around 2592000, the request used morph-api instead of your client.
Check that the token can read what the dashboards need:
TOKEN=paste-the-access-token-here
curl -sk -H "Authorization: Bearer $TOKEN" "$MORPHEUS/api/clusters?max=5" | head -c 300; echo
curl -sk -H "Authorization: Bearer $TOKEN" "$MORPHEUS/api/health" | head -c 300; echo
curl -sk -H "Authorization: Bearer $TOKEN" "$MORPHEUS/api/data-stores?max=5" | head -c 300; echo
All three should return JSON with data. A 403 means the matching role entry (Clusters, Health or Storage) is still at None.
1.4 Install the exporters on the HVM hosts
Do this on every HVM host of your Morpheus Enterprise clusters. The commands are for Ubuntu 24.04 on amd64. They need sudo and internet access from the host. If the hosts have no internet access, download the two files on another machine and copy them to the hosts with scp.
Both exporters are installed from .deb files, not from an apt repository. The HVM hosts come with the vendor's package sources only, and I prefer not to add a new source to a hypervisor just for this.
node_exporter
This is the Ubuntu package of node_exporter. Download it from the Ubuntu archive and check its SHA-256:
cd /tmp
wget http://archive.ubuntu.com/ubuntu/pool/universe/p/prometheus-node-exporter/prometheus-node-exporter_1.7.0-1ubuntu0.3_amd64.deb
echo "428751e5584dfc98e2709e0169eb1d7c1a3c439f890fae53e49d278a47cd6056 prometheus-node-exporter_1.7.0-1ubuntu0.3_amd64.deb" | sha256sum -c
The second command must print OK. Then install it:
sudo dpkg -i prometheus-node-exporter_1.7.0-1ubuntu0.3_amd64.deb
The package creates a prometheus user, runs the service as that user and starts it on port 9100. There is nothing to configure: the default collectors already include CPU, memory, disks, network and pressure information, which is all the dashboards use.
prometheus-libvirt-exporter
This exporter comes from the inovex project on GitHub. Download the package and the checksum file of the release, and check the package:
cd /tmp
wget https://github.com/inovex/prometheus-libvirt-exporter/releases/download/v2.6.0/prometheus-libvirt-exporter-2.6.0.amd64.deb
wget https://github.com/inovex/prometheus-libvirt-exporter/releases/download/v2.6.0/prometheus-libvirt-exporter-2.6.0_checksums.txt
sha256sum -c --ignore-missing prometheus-libvirt-exporter-2.6.0_checksums.txt
The last command must print prometheus-libvirt-exporter-2.6.0.amd64.deb: OK. Install it:
sudo dpkg -i prometheus-libvirt-exporter-2.6.0.amd64.deb
The service in this package runs as root. It does not need to: libvirt has a read-only socket that every local user can read, and that is enough for metrics. So add a small override that runs the service as a temporary unprivileged user instead. systemd creates this user when the service starts and removes it when it stops (DynamicUser):
sudo mkdir -p /etc/systemd/system/prometheus-libvirt-exporter.service.d
printf '[Service]\nDynamicUser=yes\n' | sudo tee /etc/systemd/system/prometheus-libvirt-exporter.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl enable prometheus-libvirt-exporter
sudo systemctl restart prometheus-libvirt-exporter
Check the host
systemctl is-active prometheus-node-exporter prometheus-libvirt-exporter
systemctl show prometheus-libvirt-exporter -p User
curl -s http://localhost:9100/metrics | grep -c '^node_'
curl -s http://localhost:9177/metrics | grep -c '^libvirt_domain_info_state'
You should see active twice, a user name that is not root, several thousand node_ lines and one libvirt_domain_info_state line per virtual machine on the host. Do not move to the next host until all four checks pass.
Neither exporter has a login. Anyone who reaches ports 9100 and 9177 can read the metrics. If the hosts have a firewall, allow these two ports only from your Prometheus server.
Removing the exporters
If you need to take them off a host again:
sudo systemctl disable --now prometheus-libvirt-exporter prometheus-node-exporter
sudo rm -r /etc/systemd/system/prometheus-libvirt-exporter.service.d
sudo systemctl daemon-reload
sudo apt purge prometheus-libvirt-exporter prometheus-node-exporter
1.5 Add the hosts to Prometheus
Add two jobs under scrape_configs in prometheus.yml, one per exporter. Replace the addresses with your HVM hosts, without the port:
- job_name: hvm-node
scrape_interval: 30s
static_configs:
- targets: ["hvm-host-01.example.com:9100", "hvm-host-02.example.com:9100"]
labels:
source: enterprise
relabel_configs:
- source_labels: [__address__]
regex: '(.+):\d+'
target_label: instance
- job_name: hvm-libvirt
scrape_interval: 30s
static_configs:
- targets: ["hvm-host-01.example.com:9177", "hvm-host-02.example.com:9177"]
labels:
source: enterprise
relabel_configs:
- source_labels: [__address__]
regex: '(.+):\d+'
target_label: instance
The labels block adds the source label described at the beginning. Use the same value in both jobs. Without it the HVM dashboards stay empty.
The relabel_configs block removes the port from the instance label. Without it, the metrics of one host would carry host:9100 from one exporter and host:9177 from the other, and the dashboards could not put a host and its virtual machines together.
The job names do not matter to the dashboards. Choose names that do not clash with jobs you already have.
The capacity dashboard draws 30-day trends. If your Prometheus keeps less than 30 days (the --storage.tsdb.retention.time flag), the trends are shorter, but nothing breaks.
Check the file and reload Prometheus:
promtool check config /etc/prometheus/prometheus.yml
curl -X POST http://localhost:9090/-/reload
The reload call only works when Prometheus runs with --web.enable-lifecycle. If it does not, restart the service instead.
Open Status > Target health in the Prometheus UI. Every host should be listed twice, once per job, and all should be UP.
Then run these two queries on the Prometheus Query page:
count(node_uname_info{source="enterprise"})
count(libvirt_domain_info_state{source="enterprise"})
The first returns the number of HVM hosts, the second the number of virtual machines defined on them.
1.6 Add the Infinity data source for Morpheus
The rest of Part 1 happens in the Grafana UI.
Install the plugin from Administration > Plugins and data > Plugins: search for Infinity and click Install.
Then go to Connections > Data sources > Add new data source > Infinity and fill in:
-
Name:
Morpheus -
URL, Headers & Params: Base URL
https://morpheus.example.com, with no path and no trailing slash -
Authentication: Bearer Token, paste the token from step 1.3, and add
https://morpheus.example.comunder Allowed hosts - Network: if Grafana does not trust the Morpheus certificate, either paste your CA under With CA Cert or switch on Skip TLS Verify
The dashboards only contain API paths such as /api/servers. Infinity puts the Base URL in front of them. So use the address Grafana can reach: the load balancer name if Morpheus runs in HA, the node name if it is a single node.
Click Save & test.
1.7 Add the Prometheus data source for the HVM hosts
Go to Connections > Data sources > Add new data source > Prometheus:
-
Name:
Prometheus HVM Hosts -
Prometheus server URL: the Prometheus from step 1.5, for example
http://prometheus.example.com:9090 -
Interval behaviour > Scrape interval:
30s, the same as in the jobs
The scrape interval matters because the dashboards calculate rates over a window based on it. If it is left at the default and your jobs run at 30 seconds, some rate graphs come out empty.
Click Save & test. Grafana should say it queried the Prometheus API successfully.
1.8 Import the dashboards
Download the dashboard files from the repository:
https://github.com/emrbaykal/morpheus-k8/tree/main/grafana-morpheus/dashboards
| File | Dashboard | Data source to pick on import |
|---|---|---|
morpheus-overview.json |
Morpheus Overview | Morpheus |
hvm-hosts-vms.json |
HVM Hosts and VMs | Prometheus HVM Hosts |
hvm-bottlenecks.json |
HVM Bottlenecks | Prometheus HVM Hosts |
hvm-capacity.json |
HVM Capacity | Prometheus HVM Hosts |
For each file, go to Dashboards > New > Import, upload it, pick the data source from the table and click Import. The files contain no addresses or names from my environment. Hosts, VMs, clusters and clouds come from the data sources.
The dashboards link to each other through the menus at the top right, so you can move between them without going back to the list.
Morpheus Overview
This one reads the Morpheus API. At the top it counts apps, hosts and VMs, clusters and clouds, and below that it lists them. Further down there is a performance row per cluster, the datastores with their used space, the health of the Morpheus appliance, the Morpheus monitoring checks and incidents, and at the bottom one table of virtual machines per cloud.
The Cluster and Cloud (with VMs) variables at the top choose what is drawn. Only clouds that have virtual machines are listed, so a Kubernetes-only cloud does not add an empty table. The cluster performance row shows the last sample Morpheus holds for each host. For history, use the HVM dashboards.
HVM Hosts and VMs
A table of hosts (CPU, memory, load per core, running VMs, cores, memory, uptime), graphs for host CPU, memory, disk IOPS, disk latency and network, then a table of all virtual machines and top 10 graphs. Use the Environment, Host and VM menus at the top to narrow it down. The same three menus are on the other two HVM dashboards.
HVM Bottlenecks
This dashboard answers the question "why is it slow". Each row covers one resource:
- CPU: pressure, load per core and vCPU wait, which is the time a virtual CPU was ready to run but had to wait for a physical core.
- Memory: pressure, used memory, swap and the VMs that page most.
- Disk: pressure, busy time, latency and the VMs with the most IOPS, the so-called noisy neighbours.
- Network: drops and errors on the host interfaces and the VMs with the most traffic.
"Pressure" here is Linux PSI (Pressure Stall Information): the share of time tasks on the host had to wait for CPU, memory or disk. Near zero is good. A value that stays high means that resource is the bottleneck.
HVM Capacity
How much is allocated against what the hosts have: the ratio of virtual CPUs to physical cores, allocated memory against host memory, and 30-day trends for CPU, memory and the number of running VMs.
1.9 Pod metrics from HKS clusters (optional)
If you run HKS, the Kubernetes clusters that Morpheus builds, there is one more dashboard. Morpheus deploys a Prometheus into the monitoring namespace of every HKS cluster, and this dashboard reads that one:
kubectl -n monitoring get svc prometheus-k8s
If Grafana runs inside the cluster, the data source URL is http://prometheus-k8s.monitoring.svc:9090. If it runs elsewhere, publish that service the way you publish other services on the cluster (ingress, load balancer or NodePort) and limit access to the Grafana server, since this Prometheus has no login.
Add a Prometheus data source with that URL, then import kubernetes-pods.json and pick it. The dashboard shows node CPU and memory and, per pod, CPU, memory, network and PVC usage, with a namespace filter.
Part 2: VM Essentials
Follow this part if you run VM Essentials. Steps 2.1 to 2.3 are done in the VM Essentials manager UI as an administrator, step 2.4 on each HVM host, step 2.5 on the Prometheus server and steps 2.6 to 2.9 in Grafana.
2.1 Create a read-only role
Go to Administration > Roles, click + Add and create a User Role named Grafana Reader.
VM Essentials has no Apps, Guidance or Monitoring entries in the role, so the list is shorter. Set only these entries to Read and leave everything else at None:
| Section | Name | Access |
|---|---|---|
| Operations | Activity | Read |
| Infrastructure | Clouds | Read |
| Infrastructure | Clusters | Read |
| Infrastructure | Compute | Read |
| Infrastructure | Storage | Read |
| Admin | Health | Read |
On the Groups tab, set the groups you want to see to Read.
2.2 Create the service user
Go to Administration > Users > + Add and create:
- Username:
grafana-reader - Name and email: anything that tells your colleagues what the account is for
- Roles:
Grafana Readeronly - Password: a long one that meets your password policy
Keep the password in a safe place. You need it again when you renew the token.
2.3 Get an API token
As far as I can tell, the VM Essentials manager has no Clients screen under Administration > Settings, so the token comes from the default morph-api client and is valid for 30 days:
VME=https://vme-manager.example.com
curl -sk -X POST "$VME/oauth/token" \
--data-urlencode grant_type=password \
--data-urlencode scope=write \
--data-urlencode client_id=morph-api \
--data-urlencode username=grafana-reader \
--data-urlencode 'password=YOUR_PASSWORD'
expires_in in the answer is around 2592000, which is 30 days. Put a reminder in your calendar to renew it (see "Renewing the tokens" below).
Check the token:
TOKEN=paste-the-access-token-here
curl -sk -H "Authorization: Bearer $TOKEN" "$VME/api/clusters?max=5" | head -c 300; echo
curl -sk -H "Authorization: Bearer $TOKEN" "$VME/api/health" | head -c 300; echo
curl -sk -H "Authorization: Bearer $TOKEN" "$VME/api/data-stores?max=5" | head -c 300; echo
All three should return JSON with data.
2.4 Install the exporters on the HVM hosts
Do this on every HVM host of your VM Essentials clusters. The commands are for Ubuntu 24.04 on amd64. They need sudo and internet access from the host. If the hosts have no internet access, download the two files on another machine and copy them to the hosts with scp.
Both exporters are installed from .deb files, not from an apt repository. The HVM hosts come with the vendor's package sources only, and I prefer not to add a new source to a hypervisor just for this.
node_exporter on VM Essentials hosts
This is the Ubuntu package of node_exporter. Download it from the Ubuntu archive and check its SHA-256:
cd /tmp
wget http://archive.ubuntu.com/ubuntu/pool/universe/p/prometheus-node-exporter/prometheus-node-exporter_1.7.0-1ubuntu0.3_amd64.deb
echo "428751e5584dfc98e2709e0169eb1d7c1a3c439f890fae53e49d278a47cd6056 prometheus-node-exporter_1.7.0-1ubuntu0.3_amd64.deb" | sha256sum -c
The second command must print OK. Then install it:
sudo dpkg -i prometheus-node-exporter_1.7.0-1ubuntu0.3_amd64.deb
The package creates a prometheus user, runs the service as that user and starts it on port 9100. There is nothing to configure: the default collectors already include CPU, memory, disks, network and pressure information, which is all the dashboards use.
prometheus-libvirt-exporter on VM Essentials hosts
This exporter comes from the inovex project on GitHub. Download the package and the checksum file of the release, and check the package:
cd /tmp
wget https://github.com/inovex/prometheus-libvirt-exporter/releases/download/v2.6.0/prometheus-libvirt-exporter-2.6.0.amd64.deb
wget https://github.com/inovex/prometheus-libvirt-exporter/releases/download/v2.6.0/prometheus-libvirt-exporter-2.6.0_checksums.txt
sha256sum -c --ignore-missing prometheus-libvirt-exporter-2.6.0_checksums.txt
The last command must print prometheus-libvirt-exporter-2.6.0.amd64.deb: OK. Install it:
sudo dpkg -i prometheus-libvirt-exporter-2.6.0.amd64.deb
The service in this package runs as root. It does not need to: libvirt has a read-only socket that every local user can read, and that is enough for metrics. So add a small override that runs the service as a temporary unprivileged user instead. systemd creates this user when the service starts and removes it when it stops (DynamicUser):
sudo mkdir -p /etc/systemd/system/prometheus-libvirt-exporter.service.d
printf '[Service]\nDynamicUser=yes\n' | sudo tee /etc/systemd/system/prometheus-libvirt-exporter.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl enable prometheus-libvirt-exporter
sudo systemctl restart prometheus-libvirt-exporter
Check the VM Essentials host
systemctl is-active prometheus-node-exporter prometheus-libvirt-exporter
systemctl show prometheus-libvirt-exporter -p User
curl -s http://localhost:9100/metrics | grep -c '^node_'
curl -s http://localhost:9177/metrics | grep -c '^libvirt_domain_info_state'
You should see active twice, a user name that is not root, several thousand node_ lines and one libvirt_domain_info_state line per virtual machine on the host. Do not move to the next host until all four checks pass.
Neither exporter has a login. Anyone who reaches ports 9100 and 9177 can read the metrics. If the hosts have a firewall, allow these two ports only from your Prometheus server.
Removing the exporters from VM Essentials hosts
If you need to take them off a host again:
sudo systemctl disable --now prometheus-libvirt-exporter prometheus-node-exporter
sudo rm -r /etc/systemd/system/prometheus-libvirt-exporter.service.d
sudo systemctl daemon-reload
sudo apt purge prometheus-libvirt-exporter prometheus-node-exporter
2.5 Add the hosts to Prometheus
Add two jobs under scrape_configs in prometheus.yml, one per exporter. Replace the addresses with your HVM hosts, without the port:
- job_name: hvm-node
scrape_interval: 30s
static_configs:
- targets: ["vme-host-01.example.com:9100", "vme-host-02.example.com:9100"]
labels:
source: vme
relabel_configs:
- source_labels: [__address__]
regex: '(.+):\d+'
target_label: instance
- job_name: hvm-libvirt
scrape_interval: 30s
static_configs:
- targets: ["vme-host-01.example.com:9177", "vme-host-02.example.com:9177"]
labels:
source: vme
relabel_configs:
- source_labels: [__address__]
regex: '(.+):\d+'
target_label: instance
The labels block adds the source label described at the beginning. Use the same value in both jobs. Without it the HVM dashboards stay empty.
The relabel_configs block removes the port from the instance label. Without it, the metrics of one host would carry host:9100 from one exporter and host:9177 from the other, and the dashboards could not put a host and its virtual machines together.
The job names do not matter to the dashboards. Choose names that do not clash with jobs you already have.
The capacity dashboard draws 30-day trends. If your Prometheus keeps less than 30 days (the --storage.tsdb.retention.time flag), the trends are shorter, but nothing breaks.
Check the file and reload Prometheus:
promtool check config /etc/prometheus/prometheus.yml
curl -X POST http://localhost:9090/-/reload
The reload call only works when Prometheus runs with --web.enable-lifecycle. If it does not, restart the service instead.
Open Status > Target health in the Prometheus UI. Every host should be listed twice, once per job, and all should be UP.
Then run these two queries on the Prometheus Query page:
count(node_uname_info{source="vme"})
count(libvirt_domain_info_state{source="vme"})
The first returns the number of HVM hosts, the second the number of virtual machines defined on them.
2.6 Add the Infinity data source for VM Essentials
The rest of Part 2 happens in the Grafana UI.
Install the plugin from Administration > Plugins and data > Plugins: search for Infinity and click Install.
Then go to Connections > Data sources > Add new data source > Infinity and fill in:
-
Name:
Morpheus VME -
URL, Headers & Params: Base URL
https://vme-manager.example.com, with no path and no trailing slash -
Authentication: Bearer Token, paste the token from step 2.3, and add
https://vme-manager.example.comunder Allowed hosts - Network: if Grafana does not trust the certificate of the VM Essentials manager, either paste your CA under With CA Cert or switch on Skip TLS Verify
The dashboards only contain API paths such as /api/servers. Infinity puts the Base URL in front of them. So use the address of the VM Essentials manager as Grafana reaches it.
Click Save & test.
2.7 Add the Prometheus data source for the HVM hosts
Go to Connections > Data sources > Add new data source > Prometheus:
-
Name:
Prometheus HVM Hosts -
Prometheus server URL: the Prometheus from step 2.5, for example
http://prometheus.example.com:9090 -
Interval behaviour > Scrape interval:
30s, the same as in the jobs
The scrape interval matters because the dashboards calculate rates over a window based on it. If it is left at the default and your jobs run at 30 seconds, some rate graphs come out empty.
Click Save & test. Grafana should say it queried the Prometheus API successfully.
2.8 Import the dashboards
Download the dashboard files from the repository:
https://github.com/emrbaykal/morpheus-k8/tree/main/grafana-morpheus/dashboards
| File | Dashboard | Data source to pick on import |
|---|---|---|
morpheus-overview-vme.json |
VM Essentials Overview | Morpheus VME |
hvm-hosts-vms.json |
HVM Hosts and VMs | Prometheus HVM Hosts |
hvm-bottlenecks.json |
HVM Bottlenecks | Prometheus HVM Hosts |
hvm-capacity.json |
HVM Capacity | Prometheus HVM Hosts |
For each file, go to Dashboards > New > Import, upload it, pick the data source from the table and click Import. The files contain no addresses or names from my environment. Hosts, VMs, clusters and clouds come from the data sources.
The dashboards link to each other through the menus at the top right, so you can move between them without going back to the list.
VM Essentials Overview
This one reads the API of the VM Essentials manager. At the top it counts hosts and VMs, clusters and clouds, and below that it lists them. Further down there is a performance row per cluster, the datastores with their used space, the health of the manager, and at the bottom one table of virtual machines per cloud. The Cluster and Cloud (with VMs) menus at the top choose what is drawn.
The HVM dashboards
The three HVM dashboards are the same files as for Morpheus Enterprise. Pick vme in the Environment menu at the top; the Host and VM menus narrow it down further.
- HVM Hosts and VMs: a table of hosts, graphs for host CPU, memory, disk and network, a table of all virtual machines and top 10 graphs.
- HVM Bottlenecks: CPU, memory, disk and network pressure on the hosts, vCPU wait, and the VMs that use each resource most.
- HVM Capacity: virtual CPUs per physical core, allocated memory against host memory, and 30-day trends.
"Pressure" is Linux PSI (Pressure Stall Information): the share of time tasks on the host had to wait for CPU, memory or disk. vCPU wait is the time a virtual CPU was ready to run but had to wait for a physical core. Near zero is good for both.
2.9 Check the result
Open HVM Hosts and VMs with vme under Environment. The Hosts table should list every VM Essentials host with its running VM count, and the graphs should start filling within a minute. Then open the VM Essentials Overview and check that the clusters, hosts and datastores match what the manager shows.
Renewing the tokens
The Morpheus Enterprise token lasts as long as you set on the grafana client. The VM Essentials token lasts 30 days. To renew either one, run the curl command from step 1.3 or 2.3 again, open the matching Infinity data source in Grafana (Morpheus or Morpheus VME), paste the new token and click Save & test.
When you renew, update every place that uses the token at the same time. The old one may stop working as soon as the new one is issued.
If you ever need to cut Grafana off immediately, disable the grafana-reader user in Morpheus or in the VM Essentials manager.
What the token can see
The Grafana Reader role cannot change anything, but it reads what the API returns for clusters and hosts, and some of those answers include connection details. The dashboards do not use those fields, but a Grafana user who can edit panels or use Explore could query them through the Infinity data source.
So treat that data source like a credential. Give the Editor and Admin roles on this Grafana only to people who could have read access to Morpheus anyway. If you run Grafana Enterprise or Grafana Cloud, you can also limit who may query the data source.
Limits and operational notes
Installing third-party packages on a hypervisor is a support question as much as a technical one. Check your vendor's support policy before you roll the exporters out to production hosts.
The HVM hosts only have the vendor's package sources, so apt upgrade never updates these two packages. Watch their releases yourself and repeat step 1.4 or 2.4 with the new files when a security fix comes out. The node_exporter link points to one exact package version, and Ubuntu can drop an older version from its archive once a newer one is published. If wget returns 404, look up the current file for Ubuntu 24.04 (noble-updates) on packages.ubuntu.com and take its SHA-256 from the same page.
Both exporters listen on every interface of the host. The firewall rule in step 1.4 is the simplest control. You can also bind them to the management address only. Replace MGMT_IP with the address Prometheus uses for the host:
# node_exporter: its options live in /etc/default/prometheus-node-exporter
echo 'ARGS="--web.listen-address=MGMT_IP:9100"' | sudo tee /etc/default/prometheus-node-exporter
# libvirt exporter: extend the override file from step 1.4 / 2.4
printf '[Service]\nDynamicUser=yes\nExecStart=\nExecStart=/usr/bin/prometheus-libvirt-exporter --web.listen-address MGMT_IP:9177\n' | sudo tee /etc/systemd/system/prometheus-libvirt-exporter.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart prometheus-node-exporter prometheus-libvirt-exporter
The empty ExecStart= line clears the start command of the package before the new one is set. Run the checks from step 1.4 again afterwards, with MGMT_IP instead of localhost.
The overview dashboards read the API in single pages. The VM table of each cloud asks for at most 500 servers, the cloud list is built from at most 2,000 VMs and the datastore list stops at 500. In a larger environment the tables are cut off without a warning, so raise the max= value in the panel query if you need more.
I tested this with five HVM hosts and about 40 virtual machines. The Prometheus side should scale well past that, but I have not measured how the bottleneck queries behave with hundreds of VMs per data source. If panels load slowly, narrow them with the Host menu first.
The curl -sk examples skip certificate checks so they work against a lab appliance. With a certificate your machine trusts, drop the k.
Checklist
Part 1, Morpheus Enterprise:
- [ ] Role
Grafana Readerwith nine entries at Read, groups at Read - [ ] User
grafana-readerwith only that role - [ ] Client
grafanawith the token lifetime you want, andexpires_inin the token answer matches it - [ ]
curlwith the token returns data from/api/clusters,/api/healthand/api/data-stores - [ ] On every HVM host: both services active, libvirt exporter not running as root, both
/metricspages answer - [ ] Firewall allows 9100 and 9177 from Prometheus only
- [ ] Prometheus jobs for both ports with
source: enterprise, every target UP,count(node_uname_info{source="enterprise"})equals the number of hosts - [ ] Data sources
MorpheusandPrometheus HVM Hostssaved and tested, scrape interval 30s - [ ] Morpheus Overview and the three HVM dashboards imported
- [ ] Optional: HKS Prometheus data source and Kubernetes Pods dashboard
Part 2, VM Essentials:
- [ ] Role
Grafana Readerwith six entries at Read, groups at Read - [ ] User
grafana-readerwith only that role - [ ]
curlwith the token returns data from/api/clusters,/api/healthand/api/data-stores, calendar reminder for the 30-day renewal - [ ] On every HVM host: both services active, libvirt exporter not running as root, both
/metricspages answer - [ ] Firewall allows 9100 and 9177 from Prometheus only
- [ ] Prometheus jobs for both ports with
source: vme, every target UP,count(node_uname_info{source="vme"})equals the number of hosts - [ ] Data sources
Morpheus VMEandPrometheus HVM Hostssaved and tested, scrape interval 30s - [ ] VM Essentials Overview and the three HVM dashboards imported, Environment set to
vme
If a panel shows "No data", open it with Edit and look at the query inspector. For the overview dashboards, a 401 means the token expired or was pasted wrong, a 403 points to a role entry still at None, and a connection error usually means the Base URL or the allowed hosts entry does not match the address Grafana uses. For the HVM dashboards, start at Status > Target health in Prometheus: a target that is down shows the error it got from the exporter. If all targets are up and the Environment menu is empty, the source label is missing from the jobs.























