feat(lite/pool/VMs): ability to snapshot selected VMs (#7021)

This commit is contained in:
Mathieu 2023-09-26 15:28:15 +00:00 committed by GitHub
parent d8530f9518
commit a3a2fda157
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 71 additions and 13 deletions

View File

@ -3,6 +3,7 @@
## **next**
- Ability to migrate selected VMs to another host (PR [#7040](https://github.com/vatesfr/xen-orchestra/pull/7040))
- Ability to snapshot selected VMs (PR [#7021](https://github.com/vatesfr/xen-orchestra/pull/7021))
## **0.1.3** (2023-09-01)

View File

@ -0,0 +1,50 @@
<template>
<MenuItem
:busy="areSomeVmsSnapshoting"
:disabled="isDisabled"
:icon="faCamera"
@click="handleSnapshot"
>
{{ $t("snapshot") }}
</MenuItem>
</template>
<script lang="ts" setup>
import MenuItem from "@/components/menu/MenuItem.vue";
import { useVmCollection } from "@/stores/xen-api/vm.store";
import { VM_OPERATION } from "@/libs/xen-api/xen-api.enums";
import type { XenApiVm } from "@/libs/xen-api/xen-api.types";
import { useXenApiStore } from "@/stores/xen-api.store";
import { faCamera } from "@fortawesome/free-solid-svg-icons";
import { computed } from "vue";
const props = defineProps<{
vmRefs: XenApiVm["$ref"][];
}>();
const { getByOpaqueRef, isOperationPending } = useVmCollection();
const vms = computed(() =>
props.vmRefs
.map((vmRef) => getByOpaqueRef(vmRef))
.filter((vm): vm is XenApiVm => vm !== undefined)
);
const areSomeVmsSnapshoting = computed(() =>
vms.value.some((vm) => isOperationPending(vm, VM_OPERATION.SNAPSHOT))
);
const isDisabled = computed(() => vms.value.length === 0 || areSomeVmsSnapshoting.value);
const handleSnapshot = () => {
const vmRefsToSnapshot = Object.fromEntries(
vms.value.map((vm) => [
vm.$ref,
`${vm.name_label}_${new Date().toISOString()}`,
])
);
return useXenApiStore().getXapi().vm.snapshot(vmRefsToSnapshot);
};
</script>
<style lang="postcss" scoped></style>

View File

@ -20,9 +20,7 @@
<MenuItem v-tooltip="$t('coming-soon')" :icon="faEdit">
{{ $t("edit-config") }}
</MenuItem>
<MenuItem v-tooltip="$t('coming-soon')" :icon="faCamera">
{{ $t("snapshot") }}
</MenuItem>
<VmActionSnapshotItem :vm-refs="selectedRefs" />
<VmActionExportItem :vm-refs="selectedRefs" />
<VmActionDeleteItem :vm-refs="selectedRefs" />
</AppMenu>
@ -37,11 +35,11 @@ import VmActionDeleteItem from "@/components/vm/VmActionItems/VmActionDeleteItem
import VmActionExportItem from "@/components/vm/VmActionItems/VmActionExportItem.vue";
import VmActionMigrateItem from "@/components/vm/VmActionItems/VmActionMigrateItem.vue";
import VmActionPowerStateItems from "@/components/vm/VmActionItems/VmActionPowerStateItems.vue";
import VmActionSnapshotItem from "@/components/vm/VmActionItems/VmActionSnapshotItem.vue";
import { vTooltip } from "@/directives/tooltip.directive";
import type { XenApiVm } from "@/libs/xen-api/xen-api.types";
import { useUiStore } from "@/stores/ui.store";
import {
faCamera,
faEdit,
faEllipsis,
faPowerOff,

View File

@ -108,7 +108,7 @@ export default class XenApi {
async loadRecords<
Type extends ObjectType,
XRecord extends ObjectTypeToRecord<Type>
XRecord extends ObjectTypeToRecord<Type>,
>(type: Type): Promise<XRecord[]> {
this.emitEvent(`${type}.beforeLoad`);
@ -134,7 +134,7 @@ export default class XenApi {
addEventListener<
Type extends ObjectType,
XRecord extends ObjectTypeToRecord<Type>
XRecord extends ObjectTypeToRecord<Type>,
>(
event: XenApiRecordAfterLoadEvent<Type>,
callback: (records: XRecord[]) => void
@ -152,7 +152,7 @@ export default class XenApi {
addEventListener<
Type extends ObjectType,
XRecord extends ObjectTypeToRecord<Type>
XRecord extends ObjectTypeToRecord<Type>,
>(
event: XenApiRecordAddEvent<Type> | XenApiRecordModEvent<Type>,
callback: (record: XRecord) => void
@ -160,7 +160,7 @@ export default class XenApi {
addEventListener<
Type extends ObjectType,
XRecord extends ObjectTypeToRecord<Type>
XRecord extends ObjectTypeToRecord<Type>,
>(
event: XenApiRecordDelEvent<Type>,
callback: (opaqueRef: XRecord["$ref"]) => void
@ -189,7 +189,7 @@ export default class XenApi {
removeEventListener<
Type extends ObjectType,
XRecord extends ObjectTypeToRecord<Type>
XRecord extends ObjectTypeToRecord<Type>,
>(
event: XenApiRecordAfterLoadEvent<Type>,
callback: (records: XRecord[]) => void
@ -197,7 +197,7 @@ export default class XenApi {
removeEventListener<
Type extends ObjectType,
XRecord extends ObjectTypeToRecord<Type>
XRecord extends ObjectTypeToRecord<Type>,
>(
event: XenApiRecordAddEvent<any> | XenApiRecordModEvent<any>,
callback: (record: XRecord) => void
@ -205,7 +205,7 @@ export default class XenApi {
removeEventListener<
Type extends ObjectType,
XRecord extends ObjectTypeToRecord<Type>
XRecord extends ObjectTypeToRecord<Type>,
>(
event: XenApiRecordDelEvent<Type>,
callback: (opaqueRef: XRecord["$ref"]) => void
@ -296,7 +296,7 @@ export default class XenApi {
XenApiVm["$ref"],
XenApiVm["power_state"]
>;
type VmRefsToClone = Record<XenApiVm["$ref"], /* Cloned VM name */ string>;
type VmRefsWithNameLabel = Record<XenApiVm["$ref"], string>;
return {
delete: (vmRefs: VmRefs) =>
@ -351,7 +351,7 @@ export default class XenApi {
)
);
},
clone: (vmRefsToClone: VmRefsToClone) => {
clone: (vmRefsToClone: VmRefsWithNameLabel) => {
const vmRefs = Object.keys(vmRefsToClone) as XenApiVm["$ref"][];
return Promise.all(
@ -371,6 +371,15 @@ export default class XenApi {
)
);
},
snapshot: (vmRefsToSnapshot: VmRefsWithNameLabel) => {
const vmRefs = Object.keys(vmRefsToSnapshot) as XenApiVm["$ref"][];
return Promise.all(
vmRefs.map((vmRef) =>
this.call("VM.snapshot", [vmRef, vmRefsToSnapshot[vmRef]])
)
);
},
};
}
}