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(xo-server/xo-web/host): display 2CRSi informations in general tab #7838

Merged
merged 12 commits into from
Jul 29, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
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
49 changes: 49 additions & 0 deletions @xen-orchestra/xapi/host.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { defer } from 'golike-defer'
import { incorrectState, operationFailed } from 'xo-common/api-errors.js'

julien-f marked this conversation as resolved.
Show resolved Hide resolved
import { getCurrentVmUuid } from './_XenStore.mjs'
import {
addIpmiSensorDataType,
containsDigit,
IPMI_SENSOR_DATA_TYPE,
IPMI_SENSOR_REGEX_BY_DATA_TYPE_BY_SUPPORTED_PRODUCT_NAME,
isRelevantIpmiSensor,
} from './host/_ipmi.mjs'

const waitAgentRestart = (xapi, hostRef, prevAgentStartTime) =>
new Promise(resolve => {
Expand Down Expand Up @@ -120,6 +127,48 @@ class Host {
await this.callAsync('host.reboot', ref)
await waitAgentRestart(this, ref, agentStartTime)
}

async getIpmiSensors(ref, { cache } = {}) {
let productName

const productNameCacheKey = this.computeCacheKey('host', ref, 'system-product-name')
if (cache?.has(productNameCacheKey)) {
productName = cache.get(productNameCacheKey)
} else {
productName = (await this.getField('host', ref, 'bios_strings'))['system-product-name']?.toLowerCase()
julien-f marked this conversation as resolved.
Show resolved Hide resolved
cache?.set(productNameCacheKey, productName)
}

if (IPMI_SENSOR_REGEX_BY_DATA_TYPE_BY_SUPPORTED_PRODUCT_NAME[productName] === undefined) {
return {}
}
const callSensorPlugin = fn => this.call(cache, 'host.call_plugin', ref, '2crsi-sensors.py', fn, {})
julien-f marked this conversation as resolved.
Show resolved Hide resolved
// https://github.com/AtaxyaNetwork/xcp-ng-xapi-plugins/tree/ipmi-sensors?tab=readme-ov-file#ipmi-sensors-parser
const [stringifiedIpmiSensors, ip] = await Promise.all([callSensorPlugin('get_info'), callSensorPlugin('get_ip')])
const ipmiSensors = JSON.parse(stringifiedIpmiSensors)

const ipmiSensorsByDataType = {}
for (const ipmiSensor of ipmiSensors) {
if (!isRelevantIpmiSensor(ipmiSensor, productName)) {
continue
}

addIpmiSensorDataType(ipmiSensor, productName)
const dataType = ipmiSensor.dataType

if (ipmiSensorsByDataType[dataType] === undefined) {
ipmiSensorsByDataType[dataType] = containsDigit(ipmiSensor.Name) ? [] : ipmiSensor
}

if (Array.isArray(ipmiSensorsByDataType[ipmiSensor.dataType])) {
ipmiSensorsByDataType[dataType].push(ipmiSensor)
}
fbeauchamp marked this conversation as resolved.
Show resolved Hide resolved
}

ipmiSensorsByDataType[IPMI_SENSOR_DATA_TYPE.generalInfo] = { ip }

return ipmiSensorsByDataType
}
}
export default Host

Expand Down
63 changes: 63 additions & 0 deletions @xen-orchestra/xapi/host/_ipmi.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import TTLCache from '@isaacs/ttlcache'

const IPMI_CACHE_TTL = 6e4

export const IPMI_SENSOR_DATA_TYPE = {
totalPower: 'totalPower',
outletTemp: 'outletTemp',
bmcStatus: 'bmcStatus',
inletTemp: 'inletTemp',
cpuTemp: 'cpuTemp',
fanStatus: 'fanStatus',
fanSpeed: 'fanSpeed',
psuStatus: 'psuStatus',
generalInfo: 'generalInfo',
unknown: 'unknown',
}

export const IPMI_SENSOR_REGEX_BY_DATA_TYPE_BY_SUPPORTED_PRODUCT_NAME = {
'mona_1.44gg': {
[IPMI_SENSOR_DATA_TYPE.totalPower]: /^total_power$/i,
[IPMI_SENSOR_DATA_TYPE.outletTemp]: /^outlet_temp$/i,
[IPMI_SENSOR_DATA_TYPE.bmcStatus]: /^bmc_status$/i,
[IPMI_SENSOR_DATA_TYPE.inletTemp]: /^psu_inlet_temp$/i,
[IPMI_SENSOR_DATA_TYPE.cpuTemp]: /^cpu[0-9]+_temp$/i,
[IPMI_SENSOR_DATA_TYPE.fanStatus]: /^fan[0-9]+_status$/i,
[IPMI_SENSOR_DATA_TYPE.fanSpeed]: /^fan[0-9]+_r_speed$/i,
[IPMI_SENSOR_DATA_TYPE.psuStatus]: /^psu[0-9]+_status$/i,
},
}
const IPMI_SENSOR_REGEX_BY_PRODUCT_NAME = Object.keys(IPMI_SENSOR_REGEX_BY_DATA_TYPE_BY_SUPPORTED_PRODUCT_NAME).reduce(
(acc, productName) => {
const regexes = Object.values(IPMI_SENSOR_REGEX_BY_DATA_TYPE_BY_SUPPORTED_PRODUCT_NAME[productName])
const combinedRegex = new RegExp(regexes.map(regex => regex.source).join('|'), 'i')
acc[productName] = combinedRegex
return acc
},
{}
)

export const IPMI_CACHE = new TTLCache({
ttl: IPMI_CACHE_TTL,
max: 1000,
})

export const isRelevantIpmiSensor = (data, productName) =>
IPMI_SENSOR_REGEX_BY_PRODUCT_NAME[productName].test(data.Name)

export const containsDigit = str => /\d/.test(str)

export const addIpmiSensorDataType = (data, productName) => {
const name = data.Name
const ipmiRegexByDataType = IPMI_SENSOR_REGEX_BY_DATA_TYPE_BY_SUPPORTED_PRODUCT_NAME[productName]

for (const dataType in ipmiRegexByDataType) {
const regex = ipmiRegexByDataType[dataType]
if (regex.test(name)) {
data.dataType = dataType
return
}
}

data.dataType = IPMI_SENSOR_DATA_TYPE.unknown
}
1 change: 1 addition & 0 deletions @xen-orchestra/xapi/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"test": "node--test"
},
"dependencies": {
"@isaacs/ttlcache": "^1.4.1",
julien-f marked this conversation as resolved.
Show resolved Hide resolved
"@vates/async-each": "^1.0.0",
"@vates/decorate-with": "^2.1.0",
"@vates/nbd-client": "^3.0.2",
Expand Down
5 changes: 3 additions & 2 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
> Users must be able to say: “Nice enhancement, I'm eager to test it”

- [Backups] Add 'report recipients' when creating a metadata backup [#7569](https://github.com/vatesfr/xen-orchestra/issues/7569) (PR [#7776](https://github.com/vatesfr/xen-orchestra/pull/7776))
- [Host/General] Display additional hardware data for 2CRSi server [#7816](https://github.com/vatesfr/xen-orchestra/issues/7816) (PR [#7838](https://github.com/vatesfr/xen-orchestra/pull/7838))

### Bug fixes

Expand All @@ -25,7 +26,7 @@
- [New SR] Add confirmation modal before creating an SR if SRs are already present in the same path (for NFS/ISCSI) [#4273](https://github.com/vatesfr/xen-orchestra/issues/4273) (PR [#7845](https://github.com/vatesfr/xen-orchestra/pull/7845))
- [XO Tasks] Reduce the number of API calls that incorrectly stay in pending status (often `sr.getAllUnhealthyVdiChainsLength`) [Forum#79281](https://xcp-ng.org/forum/post/79281) [Forum#80010](https://xcp-ng.org/forum/post/80010)
- [Plugin/backup-reports] Fix _Metadata Backup_ report not sent in some cases (PR [#7776](https://github.com/vatesfr/xen-orchestra/pull/7776))
- [Host/Advanced] Fix *Advanced Live Telemetry* link on recent XOAs
- [Host/Advanced] Fix _Advanced Live Telemetry_ link on recent XOAs

### Packages to release

Expand All @@ -46,7 +47,7 @@
- @vates/nbd-client minor
- @xen-orchestra/backups patch
- @xen-orchestra/mixins minor
- @xen-orchestra/xapi patch
- @xen-orchestra/xapi minor
- xen-api minor
- xo-server minor
- xo-server-backup-reports minor
Expand Down
11 changes: 11 additions & 0 deletions packages/xo-server/src/api/host.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createLogger } from '@xen-orchestra/log'
import assert from 'assert'
import { format } from 'json-rpc-peer'
import { incorrectState } from 'xo-common/api-errors.js'
import { IPMI_CACHE } from '@xen-orchestra/xapi/host/_ipmi.mjs'
julien-f marked this conversation as resolved.
Show resolved Hide resolved

import backupGuard from './_backupGuard.mjs'

Expand Down Expand Up @@ -592,3 +593,13 @@ getBlockdevices.params = {
getBlockdevices.resolve = {
host: ['id', 'host', 'administrate'],
}

export function getIpmiSensors({ host }) {
return this.getXapi(host).host_getIpmiSensors(host._xapiRef, { cache: IPMI_CACHE })
}
getIpmiSensors.params = {
id: { type: 'string' },
}
getIpmiSensors.resolve = {
host: ['id', 'host', 'administrate'],
}
10 changes: 10 additions & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -2844,6 +2844,16 @@ const messages = {
secondsFormat: '{seconds, plural, one {# second} other {# seconds}}',
durationFormat:
'{days, plural, =0 {} one {# day } other {# days }}{hours, plural, =0 {} one {# hour } other {# hours }}{minutes, plural, =0 {} one {# minute } other {# minutes }}{seconds, plural, =0 {} one {# second} other {# seconds}}',

// ----- IPMI -----
highestCpuTemperature: '{n, number}x CPU{n, plural, one {} other {s}} (highest: {degres})',
highestFanSpeed: '{n, number}x fan{n, plural, one {} other {s}} (highest: {speed})',
inletTemperature: 'Inlet temperature',
ipmi: 'IPMI',
nFanStatus: '{n, number}x fan{n, plural, one {} other {s}} status: {status}',
nPsuStatus: '{n, number}x PSU{n, plural, one {} other {s}} status: {status}',
outletTemperature: 'Outlet temperature',
totalPower: 'Total power',
}
forEach(messages, function (message, id) {
if (typeof message === 'string') {
Expand Down
25 changes: 22 additions & 3 deletions packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,27 @@ subscribeXostorInterfaces.forceRefresh = sr => {
subscription?.forceRefresh()
}

const subscribeHostsIpmiSensors = {}
export const subscribeIpmiSensors = host => {
const _isAdmin = isAdmin(store.getState())
const hostId = resolveId(host)

if (subscribeHostsIpmiSensors[hostId] === undefined) {
subscribeHostsIpmiSensors[hostId] = createSubscription(
async () =>
_isAdmin
? await _call('host.getIpmiSensors', {
id: hostId,
})
: undefined,
{
polling: 6e4,
}
)
}

return subscribeHostsIpmiSensors[hostId]
}
// System ============================================================

export const apiMethods = _call('system.getMethodsInfo')
Expand Down Expand Up @@ -2373,9 +2394,7 @@ export const migrateVdi = (vdi, sr, resourceSet) =>
sr_id: resolveId(sr),
})

export const setCbt = (vdi, cbt) =>
_call('vdi.set', { id: resolveId(vdi), cbt })

export const setCbt = (vdi, cbt) => _call('vdi.set', { id: resolveId(vdi), cbt })

// VBD ---------------------------------------------------------------

Expand Down
34 changes: 34 additions & 0 deletions packages/xo-web/src/icons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,40 @@
@extend .fa-share;
}

// IPMI
&-cpu-temperature {
@extend .fa;
@extend .fa-thermometer-full;
}
&-fan-speed {
@extend .fa;
@extend .fa-circle-o-notch;
}
&-fan-status {
@extend .fa;
@extend .fa-medkit;
}
&-inlet {
@extend .fa;
@extend .fa-sign-in;
}
&-ipmi {
@extend .fa;
@extend .fa-wrench;
}
&-outlet {
@extend .fa;
@extend .fa-sign-out;
}
&-psu {
@extend .fa;
@extend .fa-plug;
}
&-total-power {
@extend .fa;
@extend .fa-tachometer;
}

// VM
&-vm {
// States
Expand Down
Loading
Loading