feat(xo6/vm): add guest tools status (#10077)

This commit is contained in:
Sandrine Barrucand
2026-08-25 10:40:50 +02:00
committed by GitHub
parent d955ffc4d1
commit 14e5352a40
9 changed files with 97 additions and 41 deletions

View File

@@ -414,6 +414,8 @@
"graphics-display": "Graphics & Display",
"groups": "Groups",
"guest-tools": "Guest tools",
"guest-tools-out-of-date": "Guest tools out of date",
"guest-tools-status-unknown": "Guest tools status unknown",
"gzip": "GZIP",
"hardware": "Hardware",
"hardware-specifications": "Hardware specifications",
@@ -809,6 +811,7 @@
"no-replicated-vm": "This VM isnt being replicated. Configure a replication job to enable it.",
"no-result": "No results",
"no-role-applied": "No role applied",
"no-running-vm-detected": "No running VMs detected",
"no-schedule-available": "No schedules available",
"no-selected-vm-can-be-exported": "No selected VM can be exported",
"no-selected-vm-can-be-migrated": "No selected VM can be migrated",

View File

@@ -413,7 +413,9 @@
"gpus": "GPUs",
"graphics-display": "Graphique & Affichage",
"groups": "Groupes",
"guest-tools": "Guest Tools",
"guest-tools": "Guest tools",
"guest-tools-out-of-date": "Guest tools obsolètes",
"guest-tools-status-unknown": "Statut des guest tools inconnu",
"gzip": "GZIP",
"hardware": "Matériel",
"hardware-specifications": "Spécifications matérielles",
@@ -809,6 +811,7 @@
"no-replicated-vm": "Cette VM n'est pas répliquée. Configurez une tâche de réplication pour l'activer.",
"no-result": "Aucun résultat",
"no-role-applied": "Pas de rôle appliqué",
"no-running-vm-detected": "Aucune VM en cours d'exécution détectée",
"no-schedule-available": "Aucune planification disponible",
"no-selected-vm-can-be-exported": "Aucune VM sélectionnée ne peut être exportée",
"no-selected-vm-can-be-migrated": "Aucune VM sélectionnée ne peut être migrée",

View File

@@ -0,0 +1,34 @@
<template>
<div class="vm-guest-tools-status">
<VtsIcon
v-if="guestToolsDisplay.type !== 'not-applicable'"
v-tooltip="guestToolsDisplay.tooltip"
:name="guestToolsDisplay.icon"
size="medium"
/>
<UiLink v-if="guestToolsDisplay.type === 'missing'" size="small" :href="XCP_LINKS.GUEST_TOOLS">
{{ guestToolsDisplay.value }}
</UiLink>
<span v-else v-tooltip class="text-ellipsis">{{ guestToolsDisplay.value }}</span>
</div>
</template>
<script setup lang="ts">
import type { GuestToolsDisplay } from '@/modules/vm/composables/xo-vm-utils.composable.ts'
import { XCP_LINKS } from '@/shared/constants.ts'
import VtsIcon from '@core/components/icon/VtsIcon.vue'
import UiLink from '@core/components/ui/link/UiLink.vue'
import { vTooltip } from '@core/directives/tooltip.directive.ts'
defineProps<{
guestToolsDisplay: GuestToolsDisplay
}>()
</script>
<style scoped lang="postcss">
.vm-guest-tools-status {
display: flex;
align-items: center;
gap: 0.8rem;
}
</style>

View File

@@ -55,20 +55,7 @@
<VtsKeyValueRow :label="t('virtualization-type')" :value="virtualizationType" />
<VtsKeyValueRow :label="t('guest-tools')">
<template #value>
<div class="value">
<VtsIcon
v-if="guestToolsDisplay.value !== '-'"
v-tooltip="guestToolsDisplay.tooltip"
:name="guestToolsDisplay.type === 'link' ? 'status:halted-circle' : 'status:success-circle'"
size="medium"
/>
<UiLink v-if="guestToolsDisplay.type === 'link'" size="small" :href="XCP_LINKS.GUEST_TOOLS">
{{ guestToolsDisplay.value }}
</UiLink>
<template v-else>
<span v-tooltip class="text-ellipsis"> {{ guestToolsDisplay.value }}</span>
</template>
</div>
<VmGuestToolsStatus :guest-tools-display />
</template>
</VtsKeyValueRow>
</VtsKeyValueList>
@@ -90,9 +77,9 @@
import { useXoHostCollection } from '@/modules/host/remote-resources/use-xo-host-collection.ts'
import { useXoPoolCollection } from '@/modules/pool/remote-resources/use-xo-pool-collection.ts'
import { useXoUserResource } from '@/modules/user/remote-resources/use-xo-user.ts'
import VmGuestToolsStatus from '@/modules/vm/components/VmGuestToolsStatus.vue'
import { useXoVmUtils } from '@/modules/vm/composables/xo-vm-utils.composable.ts'
import { type FrontXoVm, useXoVmCollection } from '@/modules/vm/remote-resources/use-xo-vm-collection.ts'
import { XCP_LINKS } from '@/shared/constants.ts'
import VtsIcon from '@core/components/icon/VtsIcon.vue'
import VtsKeyValueList from '@core/components/key-value-list/VtsKeyValueList.vue'
import VtsKeyValueRow from '@core/components/key-value-row/VtsKeyValueRow.vue'
@@ -100,7 +87,6 @@ import VtsQuickInfoCard from '@core/components/quick-info-card/VtsQuickInfoCard.
import VtsTag from '@core/components/tag/VtsTag.vue'
import UiLink from '@core/components/ui/link/UiLink.vue'
import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
import { vTooltip } from '@core/directives/tooltip.directive.ts'
import { formatSize } from '@core/utils/size.util.ts'
import { HOST_POWER_STATE } from '@vates/types'
import { toLower } from 'lodash-es'

View File

@@ -76,20 +76,7 @@
<VtsCardRowKeyValue>
<template #key>{{ t('guest-tools') }}</template>
<template #value>
<div class="value">
<VtsIcon
v-if="guestToolsDisplay.value !== '-'"
v-tooltip="guestToolsDisplay.tooltip"
:name="guestToolsDisplay.type === 'link' ? 'status:halted-circle' : 'status:success-circle'"
size="medium"
/>
<UiLink v-if="guestToolsDisplay.type === 'link'" size="small" :href="XCP_LINKS.GUEST_TOOLS">
{{ guestToolsDisplay.value }}
</UiLink>
<template v-else>
<span v-tooltip class="text-ellipsis"> {{ guestToolsDisplay.value }}</span>
</template>
</div>
<VmGuestToolsStatus :guest-tools-display />
</template>
</VtsCardRowKeyValue>
<VtsCardRowKeyValue>
@@ -144,10 +131,10 @@
import { useXoHostCollection } from '@/modules/host/remote-resources/use-xo-host-collection.ts'
import { useXoPoolCollection } from '@/modules/pool/remote-resources/use-xo-pool-collection.ts'
import { useXoUserResource } from '@/modules/user/remote-resources/use-xo-user.ts'
import VmGuestToolsStatus from '@/modules/vm/components/VmGuestToolsStatus.vue'
import { useXoVmUtils } from '@/modules/vm/composables/xo-vm-utils.composable.ts'
import { type FrontXoVm, useXoVmCollection } from '@/modules/vm/remote-resources/use-xo-vm-collection.ts'
import { useXoVmTemplateCollection } from '@/modules/vm/remote-resources/use-xo-vm-template-collection.ts'
import { XCP_LINKS } from '@/shared/constants.ts'
import { useXoRoutes } from '@/shared/remote-resources/use-xo-routes.ts'
import VtsCardRowKeyValue from '@core/components/card/VtsCardRowKeyValue.vue'
import VtsCardObjectTitle from '@core/components/card-object-title/VtsCardObjectTitle.vue'
@@ -158,7 +145,6 @@ import UiLink from '@core/components/ui/link/UiLink.vue'
import UiPanelCard from '@core/components/ui/panel-card/UiPanelCard.vue'
import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
import UiUserLogo from '@core/components/ui/user-logo/UiUserLogo.vue'
import { vTooltip } from '@core/directives/tooltip.directive.ts'
import { HOST_POWER_STATE } from '@vates/types'
import { toLower } from 'lodash-es'
import { computed } from 'vue'

View File

@@ -17,11 +17,18 @@
<VtsTabularKeyValueRow :label="t('os-name')" :value="vm.os_version?.name" />
<VtsTabularKeyValueRow :label="t('os-kernel')" :value="vm.os_version?.uname" />
<VtsTabularKeyValueRow :label="t('management-agent-version')" :value="vm.pvDriversVersion" />
<VtsTabularKeyValueRow :label="t('guest-tools')">
<template #value>
<VmGuestToolsStatus :guest-tools-display />
</template>
</VtsTabularKeyValueRow>
</VtsTabularKeyValueList>
</UiCard>
</template>
<script setup lang="ts">
import VmGuestToolsStatus from '@/modules/vm/components/VmGuestToolsStatus.vue'
import { useXoVmUtils } from '@/modules/vm/composables/xo-vm-utils.composable.ts'
import type { FrontXoVm } from '@/modules/vm/remote-resources/use-xo-vm-collection.ts'
import VtsTabularKeyValueList from '@core/components/tabular-key-value-list/VtsTabularKeyValueList.vue'
import VtsTabularKeyValueRow from '@core/components/tabular-key-value-row/VtsTabularKeyValueRow.vue'
@@ -31,7 +38,9 @@ import UiTagsList from '@core/components/ui/tag/UiTagsList.vue'
import UiTitle from '@core/components/ui/title/UiTitle.vue'
import { useI18n } from 'vue-i18n'
defineProps<{ vm: FrontXoVm }>()
const { vm } = defineProps<{ vm: FrontXoVm }>()
const { t } = useI18n()
const { guestToolsDisplay } = useXoVmUtils(() => vm)
</script>

View File

@@ -10,6 +10,17 @@ import { VM_POWER_STATE } from '@vates/types'
import { computed, type MaybeRefOrGetter } from 'vue'
import { useI18n } from 'vue-i18n'
export type GuestToolsDisplay =
| {
type: 'missing' | 'outdated' | 'up-to-date' | 'unknown'
icon: IconName
value: string
tooltip: string
}
| {
type: 'not-applicable'
value: '-'
}
export function useXoVmUtils(rawVm: MaybeRefOrGetter<FrontXoVm>) {
const { t, locale } = useI18n()
@@ -48,24 +59,46 @@ export function useXoVmUtils(rawVm: MaybeRefOrGetter<FrontXoVm>) {
return vm.managementAgentDetected && vm.pvDriversDetected
}
const guestToolsDisplay = computed(() => {
const guestToolsDisplay = computed<GuestToolsDisplay>(() => {
if (vm.value.power_state !== VM_POWER_STATE.RUNNING) {
return { type: 'text', value: '-' }
return { type: 'not-applicable', value: '-' } as const
}
if (!hasGuestTools(vm.value)) {
return {
type: 'link',
type: 'missing',
icon: 'status:halted-circle',
value: t('action:install-guest-tools'),
tooltip: !vm.value.managementAgentDetected ? t('management-agent-not-detected') : t('no-xen-tools-detected'),
}
} as const
}
const value = vm.value.pvDriversVersion || t('installed')
if (vm.value.pvDriversUpToDate === false) {
return {
type: 'outdated',
icon: 'status:warning-circle',
value,
tooltip: t('guest-tools-out-of-date'),
} as const
}
if (vm.value.pvDriversUpToDate === undefined) {
return {
type: 'unknown',
icon: 'status:info-circle',
value,
tooltip: t('guest-tools-status-unknown'),
} as const
}
return {
type: 'text',
value: vm.value.pvDriversVersion || t('installed'),
type: 'up-to-date',
icon: 'status:success-circle',
value,
tooltip: t('installed'),
}
} as const
})
const isChangingState = computed(() => isVmOperationPending(vm.value, CHANGING_STATE_OPERATIONS))

View File

@@ -54,6 +54,7 @@ const vmFields = [
'startTime',
'installTime',
'pvDriversDetected',
'pvDriversUpToDate',
'managementAgentDetected',
'type',
'$VBDs',

View File

@@ -28,6 +28,7 @@
- [XO6/SR] Add dedicated Storage Repository page with general information, space usage, PBD details, custom fields (PR [#10100](https://github.com/vatesfr/xen-orchestra/pull/10100))
- [XO5/Backups] Add `Synchronize snapshots` checkbox to backup jobs to get consistent restore points (PR [#10136](https://github.com/vatesfr/xen-orchestra/pull/10136))
- [XO6/Host] Add possibility to smart reboot a host (PR [#10177](https://github.com/vatesfr/xen-orchestra/pull/10177))
- [XO6/VM] Add guest tools status on the VM Dashboard, VM System tab and VM Side panel (PR [#10077](https://github.com/vatesfr/xen-orchestra/pull/10077))
### Bug fixes