mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
Name vSphere, not Proxmox, as the owner of vSphere VM records
describeResourceInventoryOwnership checked the resource-type list
('vm', 'system-container', ...) before the platform, so any VM
mapped to Proxmox whatever platform the caller passed. A vCenter
alarm on a vSphere VM opened a Monitoring menu saying "Proxmox
remains the inventory owner", and the vSphere VM drawer's Manage
tab said "Proxmox owns this inventory record ... without deleting
it from Proxmox". Both are wrong for a user deciding whether
retiring the VM touches vCenter.
The helper also matched only the bare 'proxmox' and 'vmware'
families, while the resource drawers pass canonical platform keys
('proxmox-pve', 'vmware-vsphere', 'truenas'), so those never matched
a platform at all.
An explicit platform now decides the owner: proxmox and proxmox-*,
vmware and vmware-*, kubernetes, docker, truenas (newly named) and
agent. The resource-type guess is only a fallback when the platform
is empty or unrecognised, so ('vm', undefined) still maps to Proxmox.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "25f4131720dad07540378f4d82aa9c33b291e75d",
|
||||
"verified_at": "2026-10-06T09:55:29Z",
|
||||
"result": "passed",
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/utils/resourceMonitoringPolicy.ts"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/utils/resourceMonitoringPolicy.ts": "5471b694198b0477b2736b752a20792c03f23dfd177d98000636c115924612a6"
|
||||
},
|
||||
"routes": [
|
||||
"/alerts/overview",
|
||||
"/vmware/overview"
|
||||
],
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"height": 844
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
"Alerts > Overview on a private mock stack built from main, with one vSphere VM alarm (finance-jump-01, metadata resourceType vm, incidentProvider vmware, incidentCode vmware_alarm_state, message 'VM vm-205 has VMware alarm ...') appended to the live websocket activeAlerts snapshots, because the mock demo scenario clears VM alarms",
|
||||
"Card More > Monitoring menu with the change: header reads 'VMware vSphere remains the inventory owner' and Retire from monitoring reads 'VMware vSphere keeps the inventory record', at 1440 and 390",
|
||||
"Same menu with main's helper swapped back in under Vite in the same session: both lines read Proxmox at 1440 and 390",
|
||||
"vSphere overview, real mock VM finance-jump-01 (platformType vmware-vsphere, no injection), drawer Manage tab: retirement help reads 'vSphere owns this inventory record ... does not delete anything from vCenter'; with main's helper it read 'Proxmox owns this inventory record ... without deleting it from Proxmox'",
|
||||
"Menu at 390 opens as a body portal below the card and stays inside the viewport"
|
||||
],
|
||||
"interactions": [
|
||||
"Proxied the real websocket with Playwright routeWebSocket and appended the vSphere VM alarm to each activeAlerts array; also appended it to the /api/alerts/active REST recovery response",
|
||||
"Clicked More, then Monitoring, on the injected alarm card and read the menu header and the Retire from monitoring description",
|
||||
"Opened the finance-jump-01 drawer from the vSphere overview and switched to Manage",
|
||||
"Swapped resourceMonitoringPolicy.ts to main's version under the running Vite for a same-session before, then restored the change and re-ran"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { describeResourceInventoryOwnership } from '@/utils/resourceMonitoringPolicy';
|
||||
|
||||
const ownerOf = (resourceType?: string, platformType?: string) =>
|
||||
describeResourceInventoryOwnership(resourceType, platformType).ownerLabel;
|
||||
|
||||
describe('describeResourceInventoryOwnership', () => {
|
||||
it('names vSphere as the owner of a VMware VM instead of guessing Proxmox from the type', () => {
|
||||
const ownership = describeResourceInventoryOwnership('vm', 'vmware');
|
||||
|
||||
expect(ownership.ownerLabel).toBe('VMware vSphere');
|
||||
expect(ownership.retirementDescription).toContain('vCenter');
|
||||
expect(ownership.retirementDescription).not.toContain('Proxmox');
|
||||
});
|
||||
|
||||
it('keeps Proxmox as the owner of a VM when no platform is known', () => {
|
||||
expect(ownerOf('vm', undefined)).toBe('Proxmox');
|
||||
expect(ownerOf('vm', '')).toBe('Proxmox');
|
||||
});
|
||||
|
||||
it('lets an explicit platform outrank the resource-type guess', () => {
|
||||
expect(ownerOf('vm', 'vmware-vsphere')).toBe('VMware vSphere');
|
||||
expect(ownerOf('vm', 'truenas')).toBe('TrueNAS');
|
||||
expect(ownerOf('vm', 'kubernetes')).toBe('Kubernetes');
|
||||
expect(ownerOf('system-container', 'docker')).toBe('container runtime');
|
||||
expect(ownerOf('vm', 'agent')).toBe('Pulse agent');
|
||||
});
|
||||
|
||||
it('accepts canonical platform keys as well as platform families', () => {
|
||||
expect(ownerOf('node', 'proxmox')).toBe('Proxmox');
|
||||
expect(ownerOf('vm', 'proxmox-pve')).toBe('Proxmox');
|
||||
expect(ownerOf('pbs', 'proxmox-pbs')).toBe('Proxmox');
|
||||
expect(ownerOf('pmg', 'proxmox-pmg')).toBe('Proxmox');
|
||||
expect(ownerOf('datastore', 'vmware-vsphere')).toBe('VMware vSphere');
|
||||
});
|
||||
|
||||
it('falls back to the resource type when the platform is unknown or unset', () => {
|
||||
expect(ownerOf('pod', 'generic')).toBe('Kubernetes');
|
||||
expect(ownerOf('k8s-node')).toBe('Kubernetes');
|
||||
expect(ownerOf('app-container')).toBe('container runtime');
|
||||
expect(ownerOf('docker-host')).toBe('container runtime');
|
||||
expect(ownerOf('agent')).toBe('Pulse agent');
|
||||
expect(ownerOf('storage', 'unknown')).toBe('source system');
|
||||
});
|
||||
|
||||
it('reports only the Pulse agent as not provider-owned', () => {
|
||||
expect(describeResourceInventoryOwnership('agent').providerOwned).toBe(false);
|
||||
expect(describeResourceInventoryOwnership('vm', 'vmware').providerOwned).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -4,60 +4,86 @@ export interface ResourceInventoryOwnership {
|
||||
retirementDescription: string;
|
||||
}
|
||||
|
||||
const PROXMOX_OWNERSHIP: ResourceInventoryOwnership = {
|
||||
ownerLabel: 'Proxmox',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'Proxmox owns this inventory record. Retiring it stops Pulse attention and automation without deleting it from Proxmox. Restore active monitoring here at any time.',
|
||||
};
|
||||
|
||||
const KUBERNETES_OWNERSHIP: ResourceInventoryOwnership = {
|
||||
ownerLabel: 'Kubernetes',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'Kubernetes owns this object. Retiring it stops Pulse attention and automation without deleting the object from the cluster.',
|
||||
};
|
||||
|
||||
const VMWARE_OWNERSHIP: ResourceInventoryOwnership = {
|
||||
ownerLabel: 'VMware vSphere',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'vSphere owns this inventory record. Retiring it changes Pulse monitoring only and does not delete anything from vCenter.',
|
||||
};
|
||||
|
||||
const TRUENAS_OWNERSHIP: ResourceInventoryOwnership = {
|
||||
ownerLabel: 'TrueNAS',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'TrueNAS owns this inventory record. Retiring it changes Pulse monitoring only and does not delete anything from TrueNAS.',
|
||||
};
|
||||
|
||||
const CONTAINER_RUNTIME_OWNERSHIP: ResourceInventoryOwnership = {
|
||||
ownerLabel: 'container runtime',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'The container runtime owns this inventory record. Retiring it changes Pulse monitoring only and does not remove the runtime object.',
|
||||
};
|
||||
|
||||
const AGENT_OWNERSHIP: ResourceInventoryOwnership = {
|
||||
ownerLabel: 'Pulse agent',
|
||||
providerOwned: false,
|
||||
retirementDescription:
|
||||
'Retiring this machine stops Pulse attention and automation while keeping its history. Agent removal remains available from Machines.',
|
||||
};
|
||||
|
||||
const SOURCE_SYSTEM_OWNERSHIP: ResourceInventoryOwnership = {
|
||||
ownerLabel: 'source system',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'The source system owns this inventory record. Retiring it changes Pulse monitoring only and preserves the resource history.',
|
||||
};
|
||||
|
||||
// Callers pass either a platform family ('proxmox', 'vmware') or a canonical
|
||||
// platform key ('proxmox-pve', 'vmware-vsphere'); both name the same owner.
|
||||
function ownershipForPlatform(platform: string): ResourceInventoryOwnership | undefined {
|
||||
if (platform === 'proxmox' || platform.startsWith('proxmox-')) return PROXMOX_OWNERSHIP;
|
||||
if (platform === 'vmware' || platform.startsWith('vmware-')) return VMWARE_OWNERSHIP;
|
||||
if (platform === 'kubernetes') return KUBERNETES_OWNERSHIP;
|
||||
if (platform === 'docker') return CONTAINER_RUNTIME_OWNERSHIP;
|
||||
if (platform === 'truenas') return TRUENAS_OWNERSHIP;
|
||||
if (platform === 'agent') return AGENT_OWNERSHIP;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Fallback for callers that know only the resource type. Resource types such
|
||||
// as 'vm' are shared across platforms, so this guess must never outrank an
|
||||
// explicit platform.
|
||||
function ownershipForResourceType(type: string): ResourceInventoryOwnership {
|
||||
if (['vm', 'system-container', 'oci-container', 'pbs', 'pmg'].includes(type)) {
|
||||
return PROXMOX_OWNERSHIP;
|
||||
}
|
||||
if (type.startsWith('k8s-') || type === 'pod') return KUBERNETES_OWNERSHIP;
|
||||
if (type.startsWith('docker-') || type === 'app-container') return CONTAINER_RUNTIME_OWNERSHIP;
|
||||
if (type === 'agent') return AGENT_OWNERSHIP;
|
||||
return SOURCE_SYSTEM_OWNERSHIP;
|
||||
}
|
||||
|
||||
export function describeResourceInventoryOwnership(
|
||||
resourceType?: string,
|
||||
platformType?: string,
|
||||
): ResourceInventoryOwnership {
|
||||
const type = (resourceType || '').toLowerCase();
|
||||
const platform = (platformType || '').toLowerCase();
|
||||
const platform = (platformType || '').trim().toLowerCase();
|
||||
|
||||
if (
|
||||
platform === 'proxmox' ||
|
||||
['vm', 'system-container', 'oci-container', 'pbs', 'pmg'].includes(type)
|
||||
) {
|
||||
return {
|
||||
ownerLabel: 'Proxmox',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'Proxmox owns this inventory record. Retiring it stops Pulse attention and automation without deleting it from Proxmox. Restore active monitoring here at any time.',
|
||||
};
|
||||
}
|
||||
if (platform === 'kubernetes' || type.startsWith('k8s-') || type === 'pod') {
|
||||
return {
|
||||
ownerLabel: 'Kubernetes',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'Kubernetes owns this object. Retiring it stops Pulse attention and automation without deleting the object from the cluster.',
|
||||
};
|
||||
}
|
||||
if (platform === 'vmware') {
|
||||
return {
|
||||
ownerLabel: 'VMware vSphere',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'vSphere owns this inventory record. Retiring it changes Pulse monitoring only and does not delete anything from vCenter.',
|
||||
};
|
||||
}
|
||||
if (platform === 'docker' || type.startsWith('docker-') || type === 'app-container') {
|
||||
return {
|
||||
ownerLabel: 'container runtime',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'The container runtime owns this inventory record. Retiring it changes Pulse monitoring only and does not remove the runtime object.',
|
||||
};
|
||||
}
|
||||
if (type === 'agent' || platform === 'agent') {
|
||||
return {
|
||||
ownerLabel: 'Pulse agent',
|
||||
providerOwned: false,
|
||||
retirementDescription:
|
||||
'Retiring this machine stops Pulse attention and automation while keeping its history. Agent removal remains available from Machines.',
|
||||
};
|
||||
}
|
||||
return {
|
||||
ownerLabel: 'source system',
|
||||
providerOwned: true,
|
||||
retirementDescription:
|
||||
'The source system owns this inventory record. Retiring it changes Pulse monitoring only and preserves the resource history.',
|
||||
};
|
||||
return ownershipForPlatform(platform) ?? ownershipForResourceType(type);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user