mirror of
https://github.com/vatesfr/xen-orchestra.git
synced 2026-09-10 22:14:48 -05:00
feat(@xen-orchestra/rest-api): migrate vms/:id/actions/start (#8379)
This commit is contained in:
@@ -13,6 +13,10 @@
|
||||
"./common": {
|
||||
"default": "./dist/common.mjs",
|
||||
"types": "./dist/common.d.mts"
|
||||
},
|
||||
"./lib/vates/*": {
|
||||
"default": "./dist/lib/vates-*.mjs",
|
||||
"type": "./dist/lib/vates-*.d.mts"
|
||||
}
|
||||
},
|
||||
"type": "module",
|
||||
|
||||
7
@vates/types/src/lib/vates-task.mts
Normal file
7
@vates/types/src/lib/vates-task.mts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Branded } from '../common.mjs'
|
||||
|
||||
export type Task = {
|
||||
id: Branded<'task'>
|
||||
|
||||
run: <T>(fn: () => T) => Promise<T>
|
||||
}
|
||||
@@ -68,9 +68,22 @@ import type {
|
||||
// https://github.com/vatesfr/xen-orchestra/tree/wip-xapi-types-generator/%40xen-orchestra/xapi-generator
|
||||
// All properties added after XenServer 7.0 (dundee) release have been marked as optional
|
||||
|
||||
/**
|
||||
* Add properties injected by `xen-api`.
|
||||
* $ref property is also injected by XOLite, so she is not present here.
|
||||
*/
|
||||
type WrapperXenApi<T, Type extends string, Fn = { (): void }> = T & {
|
||||
$call: Fn
|
||||
$callAsync: Fn
|
||||
$type: Type
|
||||
$xapi: {
|
||||
call: <ReturnType>(...args: unknown[]) => Promise<ReturnType>
|
||||
callAsync: <ReturnType>(...args: unknown[]) => Promise<ReturnType>
|
||||
}
|
||||
}
|
||||
|
||||
export interface XenApiSession {
|
||||
$ref: Branded<'session'>
|
||||
$type: 'session'
|
||||
auth_user_name: string
|
||||
auth_user_sid: string
|
||||
client_certificate?: boolean
|
||||
@@ -91,12 +104,10 @@ export interface XenApiSession {
|
||||
|
||||
export interface XenApiAuth {
|
||||
$ref: Branded<'auth'>
|
||||
$type: 'auth'
|
||||
}
|
||||
|
||||
export interface XenApiSubject {
|
||||
$ref: Branded<'subject'>
|
||||
$type: 'subject'
|
||||
other_config: Record<string, string>
|
||||
roles: XenApiRole['$ref'][]
|
||||
subject_identifier: string
|
||||
@@ -105,7 +116,6 @@ export interface XenApiSubject {
|
||||
|
||||
export interface XenApiRole {
|
||||
$ref: Branded<'role'>
|
||||
$type: 'role'
|
||||
is_internal?: boolean
|
||||
name_description: string
|
||||
name_label: string
|
||||
@@ -115,7 +125,6 @@ export interface XenApiRole {
|
||||
|
||||
export interface XenApiTask {
|
||||
$ref: Branded<'task'>
|
||||
$type: 'task'
|
||||
allowed_operations: TASK_ALLOWED_OPERATIONS[]
|
||||
backtrace: string
|
||||
created?: string
|
||||
@@ -137,7 +146,6 @@ export interface XenApiTask {
|
||||
|
||||
export interface XenApiEvent {
|
||||
$ref: Branded<'event'>
|
||||
$type: 'event'
|
||||
class?: string
|
||||
id?: number
|
||||
/** @deprecated */
|
||||
@@ -151,7 +159,6 @@ export interface XenApiEvent {
|
||||
|
||||
export interface XenApiPool {
|
||||
$ref: Branded<'pool'>
|
||||
$type: 'pool'
|
||||
allowed_operations: POOL_ALLOWED_OPERATIONS[]
|
||||
blobs: Record<string, XenApiBlob['$ref']>
|
||||
client_certificate_auth_enabled?: boolean
|
||||
@@ -212,10 +219,10 @@ export interface XenApiPool {
|
||||
/** @deprecated */
|
||||
wlb_verify_cert?: boolean
|
||||
}
|
||||
export type XenApiPoolWrapped = WrapperXenApi<XenApiPool, 'pool'>
|
||||
|
||||
export interface XenApiPoolPatch {
|
||||
$ref: Branded<'pool_patch'>
|
||||
$type: 'pool_patch'
|
||||
after_apply_guidance: AFTER_APPLY_GUIDANCE[]
|
||||
host_patches: XenApiHostPatch['$ref'][]
|
||||
name_description: string
|
||||
@@ -230,7 +237,6 @@ export interface XenApiPoolPatch {
|
||||
|
||||
export interface XenApiPoolUpdate {
|
||||
$ref: Branded<'pool_update'>
|
||||
$type: 'pool_update'
|
||||
after_apply_guidance?: UPDATE_AFTER_APPLY_GUIDANCE[]
|
||||
enforce_homogeneity?: boolean
|
||||
hosts?: XenApiHost['$ref'][]
|
||||
@@ -244,9 +250,11 @@ export interface XenApiPoolUpdate {
|
||||
version?: string
|
||||
}
|
||||
|
||||
type XenApiVmCallMethods = {
|
||||
(method: 'start', start_paused: boolean, force: boolean): Promise<void>
|
||||
}
|
||||
export interface XenApiVm {
|
||||
$ref: Branded<'VM'>
|
||||
$type: 'VM'
|
||||
actions_after_crash?: ON_CRASH_BEHAVIOUR
|
||||
actions_after_reboot?: ON_NORMAL_EXIT
|
||||
actions_after_shutdown?: ON_NORMAL_EXIT
|
||||
@@ -344,10 +352,10 @@ export interface XenApiVm {
|
||||
VUSBs: XenApiVusb['$ref'][]
|
||||
xenstore_data: Record<string, string>
|
||||
}
|
||||
export type XenApiVmWrapped = WrapperXenApi<XenApiVm, 'VM', XenApiVmCallMethods>
|
||||
|
||||
export interface XenApiVmMetrics {
|
||||
$ref: Branded<'VM_metrics'>
|
||||
$type: 'VM_metrics'
|
||||
current_domain_type?: DOMAIN_TYPE
|
||||
hvm?: boolean
|
||||
install_time?: string
|
||||
@@ -369,7 +377,6 @@ export interface XenApiVmMetrics {
|
||||
|
||||
export interface XenApiVmGuestMetrics {
|
||||
$ref: Branded<'VM_guest_metrics'>
|
||||
$type: 'VM_guest_metrics'
|
||||
can_use_hotplug_vbd: TRISTATE_TYPE
|
||||
can_use_hotplug_vif: TRISTATE_TYPE
|
||||
/** @deprecated */
|
||||
@@ -391,7 +398,6 @@ export interface XenApiVmGuestMetrics {
|
||||
|
||||
export interface XenApiVmpp {
|
||||
$ref: Branded<'VMPP'>
|
||||
$type: 'VMPP'
|
||||
/** @deprecated */
|
||||
alarm_config?: Record<string, string>
|
||||
/** @deprecated */
|
||||
@@ -434,7 +440,6 @@ export interface XenApiVmpp {
|
||||
|
||||
export interface XenApiVmss {
|
||||
$ref: Branded<'VMSS'>
|
||||
$type: 'VMSS'
|
||||
enabled: boolean
|
||||
frequency?: VMSS_FREQUENCY
|
||||
last_run_time: string
|
||||
@@ -449,7 +454,6 @@ export interface XenApiVmss {
|
||||
|
||||
export interface XenApiVmAppliance {
|
||||
$ref: Branded<'VM_appliance'>
|
||||
$type: 'VM_appliance'
|
||||
allowed_operations: VM_APPLIANCE_OPERATION[]
|
||||
current_operations: Record<string, VM_APPLIANCE_OPERATION>
|
||||
name_description: string
|
||||
@@ -460,14 +464,12 @@ export interface XenApiVmAppliance {
|
||||
|
||||
export interface XenApiDrTask {
|
||||
$ref: Branded<'DR_task'>
|
||||
$type: 'DR_task'
|
||||
introduced_SRs: XenApiSr['$ref'][]
|
||||
uuid: string
|
||||
}
|
||||
|
||||
export interface XenApiHost {
|
||||
$ref: Branded<'host'>
|
||||
$type: 'host'
|
||||
address?: string
|
||||
allowed_operations: HOST_ALLOWED_OPERATIONS[]
|
||||
API_version_major?: number
|
||||
@@ -542,10 +544,10 @@ export interface XenApiHost {
|
||||
uuid: string
|
||||
virtual_hardware_platform_versions: number[]
|
||||
}
|
||||
export type XenApiHostWrapped = WrapperXenApi<XenApiHost, 'host'>
|
||||
|
||||
export interface XenApiHostCrashdump {
|
||||
$ref: Branded<'host_crashdump'>
|
||||
$type: 'host_crashdump'
|
||||
host?: XenApiHost['$ref']
|
||||
other_config: Record<string, string>
|
||||
size?: number
|
||||
@@ -555,7 +557,6 @@ export interface XenApiHostCrashdump {
|
||||
|
||||
export interface XenApiHostPatch {
|
||||
$ref: Branded<'host_patch'>
|
||||
$type: 'host_patch'
|
||||
applied?: boolean
|
||||
host?: XenApiHost['$ref']
|
||||
name_description: string
|
||||
@@ -570,7 +571,6 @@ export interface XenApiHostPatch {
|
||||
|
||||
export interface XenApiHostMetrics {
|
||||
$ref: Branded<'host_metrics'>
|
||||
$type: 'host_metrics'
|
||||
last_updated?: string
|
||||
live?: boolean
|
||||
/** @deprecated */
|
||||
@@ -582,7 +582,6 @@ export interface XenApiHostMetrics {
|
||||
|
||||
export interface XenApiHostCpu {
|
||||
$ref: Branded<'host_cpu'>
|
||||
$type: 'host_cpu'
|
||||
family?: number
|
||||
features?: string
|
||||
flags?: string
|
||||
@@ -600,7 +599,6 @@ export interface XenApiHostCpu {
|
||||
|
||||
export interface XenApiNetwork {
|
||||
$ref: Branded<'network'>
|
||||
$type: 'network'
|
||||
allowed_operations: NETWORK_OPERATIONS[]
|
||||
assigned_ips: Record<XenApiVif['$ref'], string>
|
||||
blobs: Record<string, XenApiBlob['$ref']>
|
||||
@@ -621,7 +619,6 @@ export interface XenApiNetwork {
|
||||
|
||||
export interface XenApiVif {
|
||||
$ref: Branded<'VIF'>
|
||||
$type: 'VIF'
|
||||
allowed_operations: VIF_OPERATIONS[]
|
||||
current_operations: Record<string, VIF_OPERATIONS>
|
||||
currently_attached: boolean
|
||||
@@ -651,10 +648,10 @@ export interface XenApiVif {
|
||||
uuid: string
|
||||
VM?: XenApiVm['$ref']
|
||||
}
|
||||
export type XenApiVifWrapped = WrapperXenApi<XenApiVif, 'VIF'>
|
||||
|
||||
export interface XenApiVifMetrics {
|
||||
$ref: Branded<'VIF_metrics'>
|
||||
$type: 'VIF_metrics'
|
||||
/** @deprecated */
|
||||
io_read_kbs?: number
|
||||
/** @deprecated */
|
||||
@@ -666,7 +663,6 @@ export interface XenApiVifMetrics {
|
||||
|
||||
export interface XenApiPif {
|
||||
$ref: Branded<'PIF'>
|
||||
$type: 'PIF'
|
||||
bond_master_of: XenApiBond['$ref'][]
|
||||
bond_slave_of?: XenApiBond['$ref']
|
||||
capabilities: string[]
|
||||
@@ -706,7 +702,6 @@ export interface XenApiPif {
|
||||
|
||||
export interface XenApiPifMetrics {
|
||||
$ref: Branded<'PIF_metrics'>
|
||||
$type: 'PIF_metrics'
|
||||
carrier?: boolean
|
||||
device_id?: string
|
||||
device_name?: string
|
||||
@@ -726,7 +721,6 @@ export interface XenApiPifMetrics {
|
||||
|
||||
export interface XenApiBond {
|
||||
$ref: Branded<'Bond'>
|
||||
$type: 'Bond'
|
||||
auto_update_mac?: boolean
|
||||
links_up: number
|
||||
master?: XenApiPif['$ref']
|
||||
@@ -740,7 +734,6 @@ export interface XenApiBond {
|
||||
|
||||
export interface XenApiVlan {
|
||||
$ref: Branded<'VLAN'>
|
||||
$type: 'VLAN'
|
||||
other_config: Record<string, string>
|
||||
tag: number
|
||||
tagged_PIF?: XenApiPif['$ref']
|
||||
@@ -750,7 +743,6 @@ export interface XenApiVlan {
|
||||
|
||||
export interface XenApiSm {
|
||||
$ref: Branded<'SM'>
|
||||
$type: 'SM'
|
||||
/** @deprecated */
|
||||
capabilities?: string[]
|
||||
configuration?: Record<string, string>
|
||||
@@ -770,7 +762,6 @@ export interface XenApiSm {
|
||||
|
||||
export interface XenApiSr {
|
||||
$ref: Branded<'SR'>
|
||||
$type: 'SR'
|
||||
allowed_operations: STORAGE_OPERATIONS[]
|
||||
blobs: Record<string, XenApiBlob['$ref']>
|
||||
clustered: boolean
|
||||
@@ -793,10 +784,10 @@ export interface XenApiSr {
|
||||
VDIs: XenApiVdi['$ref'][]
|
||||
virtual_allocation?: number
|
||||
}
|
||||
export type XenApiSrWrapped = WrapperXenApi<XenApiSr, 'SR'>
|
||||
|
||||
export interface XenApiSrStat {
|
||||
$ref: Branded<'sr_stat'>
|
||||
$type: 'sr_stat'
|
||||
clustered?: boolean
|
||||
free_space?: number
|
||||
health?: SR_HEALTH
|
||||
@@ -808,7 +799,6 @@ export interface XenApiSrStat {
|
||||
|
||||
export interface XenApiProbeResult {
|
||||
$ref: Branded<'probe_result'>
|
||||
$type: 'probe_result'
|
||||
complete?: boolean
|
||||
configuration?: Record<string, string>
|
||||
extra_info?: Record<string, string>
|
||||
@@ -817,13 +807,11 @@ export interface XenApiProbeResult {
|
||||
|
||||
export interface XenApiLvhd {
|
||||
$ref: Branded<'LVHD'>
|
||||
$type: 'LVHD'
|
||||
uuid: string
|
||||
}
|
||||
|
||||
export interface XenApiVdi {
|
||||
$ref: Branded<'VDI'>
|
||||
$type: 'VDI'
|
||||
allow_caching: boolean
|
||||
allowed_operations: VDI_OPERATIONS[]
|
||||
cbt_enabled?: boolean
|
||||
@@ -858,10 +846,10 @@ export interface XenApiVdi {
|
||||
virtual_size?: number
|
||||
xenstore_data: Record<string, string>
|
||||
}
|
||||
export type XenApiVdiWrapped = WrapperXenApi<XenApiVdi, 'VDI'>
|
||||
|
||||
export interface XenApiVbd {
|
||||
$ref: Branded<'VBD'>
|
||||
$type: 'VBD'
|
||||
allowed_operations: VBD_OPERATIONS[]
|
||||
bootable?: boolean
|
||||
current_operations: Record<string, VBD_OPERATIONS>
|
||||
@@ -886,10 +874,10 @@ export interface XenApiVbd {
|
||||
VDI?: XenApiVdi['$ref']
|
||||
VM?: XenApiVm['$ref']
|
||||
}
|
||||
export type XenApiVbdWrapped = WrapperXenApi<XenApiVbd, 'VBD'>
|
||||
|
||||
export interface XenApiVbdMetrics {
|
||||
$ref: Branded<'VBD_metrics'>
|
||||
$type: 'VBD_metrics'
|
||||
/** @deprecated */
|
||||
io_read_kbs?: number
|
||||
/** @deprecated */
|
||||
@@ -903,7 +891,6 @@ export interface XenApiVbdMetrics {
|
||||
|
||||
export interface XenApiPbd {
|
||||
$ref: Branded<'PBD'>
|
||||
$type: 'PBD'
|
||||
currently_attached?: boolean
|
||||
device_config?: Record<string, string>
|
||||
host?: XenApiHost['$ref']
|
||||
@@ -914,7 +901,6 @@ export interface XenApiPbd {
|
||||
|
||||
export interface XenApiCrashdump {
|
||||
$ref: Branded<'crashdump'>
|
||||
$type: 'crashdump'
|
||||
other_config: Record<string, string>
|
||||
uuid: string
|
||||
VDI?: XenApiVdi['$ref']
|
||||
@@ -923,7 +909,6 @@ export interface XenApiCrashdump {
|
||||
|
||||
export interface XenApiVtpm {
|
||||
$ref: Branded<'VTPM'>
|
||||
$type: 'VTPM'
|
||||
allowed_operations: VTPM_OPERATIONS[]
|
||||
backend?: XenApiVm['$ref']
|
||||
current_operations: Record<string, VTPM_OPERATIONS>
|
||||
@@ -933,10 +918,10 @@ export interface XenApiVtpm {
|
||||
uuid: string
|
||||
VM?: XenApiVm['$ref']
|
||||
}
|
||||
export type XenApiVtpmWrapped = WrapperXenApi<XenApiVtpm, 'VTPM'>
|
||||
|
||||
export interface XenApiConsole {
|
||||
$ref: Branded<'console'>
|
||||
$type: 'console'
|
||||
location?: string
|
||||
other_config?: Record<string, string>
|
||||
protocol?: CONSOLE_PROTOCOL
|
||||
@@ -946,7 +931,6 @@ export interface XenApiConsole {
|
||||
|
||||
export interface XenApiUser {
|
||||
$ref: Branded<'user'>
|
||||
$type: 'user'
|
||||
fullname?: string
|
||||
other_config: Record<string, string>
|
||||
short_name?: string
|
||||
@@ -955,7 +939,6 @@ export interface XenApiUser {
|
||||
|
||||
export interface XenApiDataSource {
|
||||
$ref: Branded<'data_source'>
|
||||
$type: 'data_source'
|
||||
enabled?: boolean
|
||||
max?: number
|
||||
min?: number
|
||||
@@ -968,7 +951,6 @@ export interface XenApiDataSource {
|
||||
|
||||
export interface XenApiBlob {
|
||||
$ref: Branded<'blob'>
|
||||
$type: 'blob'
|
||||
last_updated?: string
|
||||
mime_type?: string
|
||||
name_description: string
|
||||
@@ -980,7 +962,6 @@ export interface XenApiBlob {
|
||||
|
||||
export interface XenApiMessage {
|
||||
$ref: Branded<'message'>
|
||||
$type: 'message'
|
||||
body?: string
|
||||
cls?: CLS
|
||||
name?: string
|
||||
@@ -992,7 +973,6 @@ export interface XenApiMessage {
|
||||
|
||||
export interface XenApiSecret {
|
||||
$ref: Branded<'secret'>
|
||||
$type: 'secret'
|
||||
other_config: Record<string, string>
|
||||
uuid: string
|
||||
value?: string
|
||||
@@ -1000,7 +980,6 @@ export interface XenApiSecret {
|
||||
|
||||
export interface XenApiTunnel {
|
||||
$ref: Branded<'tunnel'>
|
||||
$type: 'tunnel'
|
||||
access_PIF?: XenApiPif['$ref']
|
||||
other_config: Record<string, string>
|
||||
protocol?: TUNNEL_PROTOCOL
|
||||
@@ -1011,7 +990,6 @@ export interface XenApiTunnel {
|
||||
|
||||
export interface XenApiNetworkSriov {
|
||||
$ref: Branded<'network_sriov'>
|
||||
$type: 'network_sriov'
|
||||
configuration_mode?: SRIOV_CONFIGURATION_MODE
|
||||
logical_PIF?: XenApiPif['$ref']
|
||||
physical_PIF?: XenApiPif['$ref']
|
||||
@@ -1021,7 +999,6 @@ export interface XenApiNetworkSriov {
|
||||
|
||||
export interface XenApiPci {
|
||||
$ref: Branded<'PCI'>
|
||||
$type: 'PCI'
|
||||
class_name: string
|
||||
dependencies: XenApiPci['$ref'][]
|
||||
device_name: string
|
||||
@@ -1037,7 +1014,6 @@ export interface XenApiPci {
|
||||
|
||||
export interface XenApiPgpu {
|
||||
$ref: Branded<'PGPU'>
|
||||
$type: 'PGPU'
|
||||
compatibility_metadata?: Record<string, string>
|
||||
dom0_access: PGPU_DOM0_ACCESS
|
||||
enabled_VGPU_types: XenApiVgpuType['$ref'][]
|
||||
@@ -1054,7 +1030,6 @@ export interface XenApiPgpu {
|
||||
|
||||
export interface XenApiGpuGroup {
|
||||
$ref: Branded<'GPU_group'>
|
||||
$type: 'GPU_group'
|
||||
allocation_algorithm: ALLOCATION_ALGORITHM
|
||||
enabled_VGPU_types: XenApiVgpuType['$ref'][]
|
||||
GPU_types: string[]
|
||||
@@ -1069,7 +1044,6 @@ export interface XenApiGpuGroup {
|
||||
|
||||
export interface XenApiVgpu {
|
||||
$ref: Branded<'VGPU'>
|
||||
$type: 'VGPU'
|
||||
compatibility_metadata?: Record<string, string>
|
||||
currently_attached: boolean
|
||||
device: string
|
||||
@@ -1083,10 +1057,10 @@ export interface XenApiVgpu {
|
||||
uuid: string
|
||||
VM?: XenApiVm['$ref']
|
||||
}
|
||||
export type XenApiVgpuWrapped = WrapperXenApi<XenApiVgpu, 'VGPU'>
|
||||
|
||||
export interface XenApiVgpuType {
|
||||
$ref: Branded<'VGPU_type'>
|
||||
$type: 'VGPU_type'
|
||||
compatible_types_in_vm?: XenApiVgpuType['$ref'][]
|
||||
enabled_on_GPU_groups: XenApiGpuGroup['$ref'][]
|
||||
enabled_on_PGPUs: XenApiPgpu['$ref'][]
|
||||
@@ -1107,7 +1081,6 @@ export interface XenApiVgpuType {
|
||||
|
||||
export interface XenApiPvsSite {
|
||||
$ref: Branded<'PVS_site'>
|
||||
$type: 'PVS_site'
|
||||
cache_storage?: XenApiPvsCacheStorage['$ref'][]
|
||||
name_description?: string
|
||||
name_label?: string
|
||||
@@ -1119,7 +1092,6 @@ export interface XenApiPvsSite {
|
||||
|
||||
export interface XenApiPvsServer {
|
||||
$ref: Branded<'PVS_server'>
|
||||
$type: 'PVS_server'
|
||||
addresses?: string[]
|
||||
first_port?: number
|
||||
last_port?: number
|
||||
@@ -1129,7 +1101,6 @@ export interface XenApiPvsServer {
|
||||
|
||||
export interface XenApiPvsProxy {
|
||||
$ref: Branded<'PVS_proxy'>
|
||||
$type: 'PVS_proxy'
|
||||
currently_attached?: boolean
|
||||
site?: XenApiPvsSite['$ref']
|
||||
status?: PVS_PROXY_STATUS
|
||||
@@ -1139,7 +1110,6 @@ export interface XenApiPvsProxy {
|
||||
|
||||
export interface XenApiPvsCacheStorage {
|
||||
$ref: Branded<'PVS_cache_storage'>
|
||||
$type: 'PVS_cache_storage'
|
||||
host?: XenApiHost['$ref']
|
||||
site?: XenApiPvsSite['$ref']
|
||||
size?: number
|
||||
@@ -1150,7 +1120,6 @@ export interface XenApiPvsCacheStorage {
|
||||
|
||||
export interface XenApiFeature {
|
||||
$ref: Branded<'Feature'>
|
||||
$type: 'Feature'
|
||||
enabled?: boolean
|
||||
experimental?: boolean
|
||||
host?: XenApiHost['$ref']
|
||||
@@ -1162,7 +1131,6 @@ export interface XenApiFeature {
|
||||
|
||||
export interface XenApiSdnController {
|
||||
$ref: Branded<'SDN_controller'>
|
||||
$type: 'SDN_controller'
|
||||
address?: string
|
||||
port?: number
|
||||
protocol?: SDN_CONTROLLER_PROTOCOL
|
||||
@@ -1171,7 +1139,6 @@ export interface XenApiSdnController {
|
||||
|
||||
export interface XenApiVdiNbdServerInfo {
|
||||
$ref: Branded<'vdi_nbd_server_info'>
|
||||
$type: 'vdi_nbd_server_info'
|
||||
address?: string
|
||||
cert?: string
|
||||
exportname?: string
|
||||
@@ -1181,7 +1148,6 @@ export interface XenApiVdiNbdServerInfo {
|
||||
|
||||
export interface XenApiPusb {
|
||||
$ref: Branded<'PUSB'>
|
||||
$type: 'PUSB'
|
||||
description?: string
|
||||
host?: XenApiHost['$ref']
|
||||
other_config?: Record<string, string>
|
||||
@@ -1200,7 +1166,6 @@ export interface XenApiPusb {
|
||||
|
||||
export interface XenApiUsbGroup {
|
||||
$ref: Branded<'USB_group'>
|
||||
$type: 'USB_group'
|
||||
name_description?: string
|
||||
name_label?: string
|
||||
other_config?: Record<string, string>
|
||||
@@ -1211,7 +1176,6 @@ export interface XenApiUsbGroup {
|
||||
|
||||
export interface XenApiVusb {
|
||||
$ref: Branded<'VUSB'>
|
||||
$type: 'VUSB'
|
||||
allowed_operations: VUSB_OPERATIONS[]
|
||||
current_operations: Record<string, VUSB_OPERATIONS>
|
||||
currently_attached: boolean
|
||||
@@ -1223,7 +1187,6 @@ export interface XenApiVusb {
|
||||
|
||||
export interface XenApiCluster {
|
||||
$ref: Branded<'Cluster'>
|
||||
$type: 'Cluster'
|
||||
allowed_operations: CLUSTER_OPERATION[]
|
||||
cluster_config?: Record<string, string>
|
||||
cluster_hosts?: XenApiClusterHost['$ref'][]
|
||||
@@ -1243,7 +1206,6 @@ export interface XenApiCluster {
|
||||
|
||||
export interface XenApiClusterHost {
|
||||
$ref: Branded<'Cluster_host'>
|
||||
$type: 'Cluster_host'
|
||||
allowed_operations: CLUSTER_HOST_OPERATION[]
|
||||
cluster?: XenApiCluster['$ref']
|
||||
current_operations: Record<string, CLUSTER_HOST_OPERATION>
|
||||
@@ -1259,7 +1221,6 @@ export interface XenApiClusterHost {
|
||||
|
||||
export interface XenApiCertificate {
|
||||
$ref: Branded<'Certificate'>
|
||||
$type: 'Certificate'
|
||||
fingerprint?: string
|
||||
host?: XenApiHost['$ref']
|
||||
name?: string
|
||||
@@ -1271,7 +1232,6 @@ export interface XenApiCertificate {
|
||||
|
||||
export interface XenApiRepository {
|
||||
$ref: Branded<'Repository'>
|
||||
$type: 'Repository'
|
||||
binary_url?: string
|
||||
gpgkey_path?: string
|
||||
hash?: string
|
||||
@@ -1286,7 +1246,6 @@ export interface XenApiRepository {
|
||||
|
||||
export interface XenApiObserver {
|
||||
$ref: Branded<'Observer'>
|
||||
$type: 'Observer'
|
||||
attributes?: Record<string, string>
|
||||
components?: string[]
|
||||
enabled?: boolean
|
||||
@@ -1365,3 +1324,14 @@ export type XenApiRecord =
|
||||
| XenApiCertificate
|
||||
| XenApiRepository
|
||||
| XenApiObserver
|
||||
|
||||
export type WrappedXenApiRecord =
|
||||
| XenApiHostWrapped
|
||||
| XenApiPoolWrapped
|
||||
| XenApiSrWrapped
|
||||
| XenApiVbdWrapped
|
||||
| XenApiVdiWrapped
|
||||
| XenApiVgpuWrapped
|
||||
| XenApiVifWrapped
|
||||
| XenApiVmWrapped
|
||||
| XenApiVtpmWrapped
|
||||
|
||||
@@ -30,6 +30,7 @@ class Foo extends Controller {
|
||||
@Example(['foo', 'bar'])
|
||||
@Get('{id}')
|
||||
@Security('*')
|
||||
@SuccessResponse(202)
|
||||
@Response(404)
|
||||
getFoo(@Path() id: string) {
|
||||
return this.getFoo(id)
|
||||
|
||||
@@ -48,6 +48,7 @@ class Foo extends Controller {
|
||||
@Example(['foo', 'bar'])
|
||||
@Get('{id}')
|
||||
@Security('*')
|
||||
@SuccessResponse(202)
|
||||
@Response(404)
|
||||
getFoo(@Path() id: string) {
|
||||
return this.getFoo(id)
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import * as CM from 'complex-matcher'
|
||||
import { Controller } from 'tsoa'
|
||||
import { Controller, HttpStatusCodeLiteral } from 'tsoa'
|
||||
import { Request } from 'express'
|
||||
import type { XapiXoRecord } from '@vates/types/xo'
|
||||
|
||||
import { BASE_URL } from '../index.mjs'
|
||||
import { RestApi } from '../rest-api/rest-api.mjs'
|
||||
import { makeObjectMapper } from '../helpers/object-wrapper.helper.mjs'
|
||||
import type { WithHref } from '../helpers/helper.type.mjs'
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
export abstract class XapiXoController<T extends XapiXoRecord> extends Controller {
|
||||
#type: T['type']
|
||||
restApi: RestApi
|
||||
@@ -34,4 +37,43 @@ export abstract class XapiXoController<T extends XapiXoRecord> extends Controlle
|
||||
|
||||
return mappedObjects
|
||||
}
|
||||
|
||||
getXapiObject(maybeId: T['id'] | T) {
|
||||
return this.restApi.getXapiObject<T>(maybeId, this.#type)
|
||||
}
|
||||
|
||||
/**
|
||||
* statusCode must represent the status code in case of a synchronous request. Default 200
|
||||
*/
|
||||
async createAction<CbType>(
|
||||
cb: () => CbType,
|
||||
{
|
||||
statusCode = 200,
|
||||
sync = false,
|
||||
taskProperties,
|
||||
}: {
|
||||
statusCode?: HttpStatusCodeLiteral
|
||||
sync?: boolean
|
||||
taskProperties: { name: string; objectId: T['id']; args?: Record<string, unknown>; [key: string]: unknown }
|
||||
}
|
||||
) {
|
||||
taskProperties.name = 'REST API: ' + taskProperties.name
|
||||
taskProperties.type = 'xo:rest-api:action'
|
||||
|
||||
const task = this.restApi.tasks.create(taskProperties)
|
||||
const pResult = task.run(cb)
|
||||
|
||||
if (sync) {
|
||||
this.setStatus(statusCode)
|
||||
return pResult
|
||||
} else {
|
||||
pResult.catch(noop)
|
||||
const location = `${BASE_URL}/tasks/${task.id}`
|
||||
this.setStatus(202)
|
||||
this.setHeader('Location', location)
|
||||
this.setHeader('Content-Type', 'text/plain')
|
||||
|
||||
return location
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import type { WithHref } from './helper.type.mjs'
|
||||
const { join } = path.posix
|
||||
|
||||
export function makeObjectMapper<T extends XapiXoRecord>(req: Request, path = req.path) {
|
||||
const makeUrl = ({ id }: T) => join(baseUrl, path, typeof id === 'number' ? String(id) : id)
|
||||
const makeUrl = ({ id }: T) => join(path, typeof id === 'number' ? String(id) : id)
|
||||
let objectMapper: (object: T) => string | WithHref<Partial<T>> | WithHref<T>
|
||||
|
||||
const { query, baseUrl } = req
|
||||
const { query } = req
|
||||
const { fields } = query
|
||||
if (fields === '*') {
|
||||
objectMapper = object => ({
|
||||
|
||||
@@ -13,6 +13,8 @@ import type { XoApp } from './rest-api/rest-api.type.mjs'
|
||||
const require = createRequire(import.meta.url)
|
||||
const swaggerOpenApiSpec = require('../open-api/spec/swagger.json')
|
||||
|
||||
export const BASE_URL = '/rest/v0'
|
||||
|
||||
export default function setupRestApi(express: Express, xoApp: XoApp) {
|
||||
setupContainer(xoApp)
|
||||
RegisterRoutes(express)
|
||||
@@ -20,8 +22,8 @@ export default function setupRestApi(express: Express, xoApp: XoApp) {
|
||||
// do not register the doc at the root level, or it may lead to unwated behaviour
|
||||
// uncomment when all endpoints are migrated to this API
|
||||
// express.get('/rest/v0', (_req, res) => res.redirect('/rest/v0/docs'))
|
||||
express.use('/rest/v0/docs', swaggerUi.serve, swaggerUi.setup(swaggerOpenApiSpec))
|
||||
express.use(`${BASE_URL}/docs`, swaggerUi.serve, swaggerUi.setup(swaggerOpenApiSpec))
|
||||
|
||||
express.use('/rest/v0', tsoaToXoErrorHandler)
|
||||
express.use('/rest/v0', genericErrorHandler)
|
||||
express.use(BASE_URL, tsoaToXoErrorHandler)
|
||||
express.use(BASE_URL, genericErrorHandler)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export default function genericErrorHandler(error: unknown, req: Request, res: R
|
||||
return
|
||||
}
|
||||
|
||||
const responseError: { error: string; info?: string } = { error: error.message }
|
||||
if (noSuchObject.is(error)) {
|
||||
res.status(404)
|
||||
} else if (unauthorized.is(error) || forbiddenOperation.is(error) || featureUnauthorized.is(error)) {
|
||||
@@ -32,11 +33,14 @@ export default function genericErrorHandler(error: unknown, req: Request, res: R
|
||||
} else if (notImplemented.is(error)) {
|
||||
res.status(501)
|
||||
} else {
|
||||
if (error.name === 'XapiError') {
|
||||
responseError.info = 'This is a XenServer/XCP-ng error, not an XO error'
|
||||
}
|
||||
res.status(500)
|
||||
log.error(error)
|
||||
}
|
||||
|
||||
log.info(`[${req.method}] ${req.path} (${res.statusCode})`)
|
||||
|
||||
res.json({ error: error.message })
|
||||
res.json(responseError)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,12 @@ export type Unbrand<T> = {
|
||||
: T[K]
|
||||
}
|
||||
|
||||
export const actionAsyncroneResp = {
|
||||
status: 202,
|
||||
description: 'Action executed asynchronously',
|
||||
produce: 'text/plain',
|
||||
} as const
|
||||
|
||||
export const unauthorizedResp = {
|
||||
status: 401,
|
||||
description: 'Authentication required',
|
||||
@@ -23,6 +29,11 @@ export const notFoundResp = {
|
||||
description: 'Resource not found',
|
||||
} as const
|
||||
|
||||
export const noContentResp = {
|
||||
status: 204,
|
||||
description: 'No content',
|
||||
} as const
|
||||
|
||||
export const internalServerErrorResp = {
|
||||
status: 500,
|
||||
description: 'Internal server error, XenServer/XCP-ng error',
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const taskLocation = '/rest/v0/tasks/0m7kl0j9l'
|
||||
@@ -9,6 +9,10 @@ export class RestApi {
|
||||
this.#xoApp = xoApp
|
||||
}
|
||||
|
||||
get tasks() {
|
||||
return this.#xoApp.tasks
|
||||
}
|
||||
|
||||
get xoApp() {
|
||||
return this.#xoApp
|
||||
}
|
||||
@@ -25,6 +29,10 @@ export class RestApi {
|
||||
return this.#xoApp.getObjectsByType(type, opts)
|
||||
}
|
||||
|
||||
getXapiObject<T extends XapiXoRecord>(maybeId: T['id'] | T, type: T['type']) {
|
||||
return this.#xoApp.getXapiObject<T>(maybeId, type)
|
||||
}
|
||||
|
||||
runWithApiContext(...args: Parameters<XoApp['runWithApiContext']>) {
|
||||
return this.#xoApp.runWithApiContext(...args)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
import type { EventEmitter } from 'node:events'
|
||||
import type { Task } from '@vates/types/lib/vates/task'
|
||||
import type { XapiHostStats, XapiVmStats, XapiStatsGranularity } from '@vates/types/common'
|
||||
import type {
|
||||
XenApiHostWrapped,
|
||||
XenApiPoolWrapped,
|
||||
XenApiSrWrapped,
|
||||
XenApiVbdWrapped,
|
||||
XenApiVdiWrapped,
|
||||
XenApiVgpuWrapped,
|
||||
XenApiVifWrapped,
|
||||
XenApiVmWrapped,
|
||||
XenApiVtpmWrapped,
|
||||
} from '@vates/types/xen-api'
|
||||
import type { XoHost, XoUser, XapiXoRecord, XoVm } from '@vates/types/xo'
|
||||
|
||||
type XapiRecordByXapiXoRecord = {
|
||||
host: XenApiHostWrapped
|
||||
pool: XenApiPoolWrapped
|
||||
SR: XenApiSrWrapped
|
||||
VBD: XenApiVbdWrapped
|
||||
VDI: XenApiVdiWrapped
|
||||
VGPU: XenApiVgpuWrapped
|
||||
VIF: XenApiVifWrapped
|
||||
VM: XenApiVmWrapped
|
||||
'VM-controller': XenApiVmWrapped
|
||||
'VM-snapshot': XenApiVmWrapped
|
||||
'VM-template': XenApiVmWrapped
|
||||
VTPM: XenApiVtpmWrapped
|
||||
}
|
||||
|
||||
export type XoApp = {
|
||||
tasks: EventEmitter & {
|
||||
create: (params: { name: string; objectId?: string; type?: string }) => Task
|
||||
}
|
||||
|
||||
// methods ------------
|
||||
authenticateUser: (
|
||||
credentials: { token?: string; username?: string; password?: string },
|
||||
userData?: { ip?: string },
|
||||
@@ -13,6 +46,7 @@ export type XoApp = {
|
||||
opts?: { filter?: string; limit?: number }
|
||||
) => Record<T['id'], T>
|
||||
getXapiHostStats: (hostId: XoHost['id'], granularity?: XapiStatsGranularity) => Promise<XapiHostStats>
|
||||
getXapiObject: <T extends XapiXoRecord>(maybeId: T['id'] | T, type: T['type']) => XapiRecordByXapiXoRecord[T['type']]
|
||||
getXapiVmStats: (vmId: XoVm['id'], granularity?: XapiStatsGranularity) => Promise<XapiVmStats>
|
||||
runWithApiContext: (user: XoUser, fn: () => void) => Promise<unknown>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
import { Example, Get, Path, Queries, Query, Request, Response, Route, Security, Tags } from 'tsoa'
|
||||
import {
|
||||
Example,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Queries,
|
||||
Query,
|
||||
Request,
|
||||
Response,
|
||||
Route,
|
||||
Security,
|
||||
Tags,
|
||||
SuccessResponse,
|
||||
} from 'tsoa'
|
||||
import { Request as ExRequest } from 'express'
|
||||
import { inject } from 'inversify'
|
||||
import { incorrectState, invalidParameters } from 'xo-common/api-errors.js'
|
||||
@@ -6,9 +19,17 @@ import { provide } from 'inversify-binding-decorators'
|
||||
import type { XapiStatsGranularity, XapiVmStats, XoVm } from '@vates/types'
|
||||
|
||||
import { CollectionQueryParams } from '../open-api/common/request.common.mjs'
|
||||
import { notFoundResp, unauthorizedResp, type Unbrand } from '../open-api/common/response.common.mjs'
|
||||
import {
|
||||
actionAsyncroneResp,
|
||||
internalServerErrorResp,
|
||||
noContentResp,
|
||||
notFoundResp,
|
||||
unauthorizedResp,
|
||||
type Unbrand,
|
||||
} from '../open-api/common/response.common.mjs'
|
||||
import { partialVms, vm, vmIds, vmStatsExample } from '../open-api/oa-examples/vm.oa-example.mjs'
|
||||
import { RestApi } from '../rest-api/rest-api.mjs'
|
||||
import { taskLocation } from '../open-api/oa-examples/task.oa-example.mjs'
|
||||
import type { WithHref } from '../helpers/helper.type.mjs'
|
||||
import { XapiXoController } from '../abstract-classes/xapi-xo-controller.mjs'
|
||||
|
||||
@@ -76,4 +97,27 @@ export class VmController extends XapiXoController<XoVm> {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @example id "f07ab729-c0e8-721c-45ec-f11276377030"
|
||||
*/
|
||||
@Example(taskLocation)
|
||||
@Post('{id}/actions/start')
|
||||
@SuccessResponse(actionAsyncroneResp.status, actionAsyncroneResp.description, actionAsyncroneResp.produce)
|
||||
@Response(noContentResp.status, noContentResp.description)
|
||||
@Response(notFoundResp.status, notFoundResp.description)
|
||||
@Response(internalServerErrorResp.status, internalServerErrorResp.description)
|
||||
async startVm(@Path() id: string, @Query() sync?: boolean) {
|
||||
const vmId = id as XoVm['id']
|
||||
const action = () => this.getXapiObject(vmId).$callAsync('start', false, false)
|
||||
|
||||
return this.createAction(action, {
|
||||
sync,
|
||||
statusCode: noContentResp.status,
|
||||
taskProperties: {
|
||||
name: 'start VM',
|
||||
objectId: vmId,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
- **Migrated REST API endpoints**:
|
||||
- `/rest/v0/vms/<vm-id>/stats` (PR [#8359](https://github.com/vatesfr/xen-orchestra/pull/8359))
|
||||
- `/rest/v0/vms/<vm-id>/actions/start` (PR [#8379](https://github.com/vatesfr/xen-orchestra/pull/8379))
|
||||
- `/rest/v0/hosts` (PR [#8372](https://github.com/vatesfr/xen-orchestra/pull/8372))
|
||||
- `/rest/v0/hosts/<host-id>` (PR [#8372](https://github.com/vatesfr/xen-orchestra/pull/8372))
|
||||
- `/rest/v0/hosts/<host-id>/stats` (PR [#8372](https://github.com/vatesfr/xen-orchestra/pull/8372))
|
||||
|
||||
@@ -605,7 +605,16 @@ export default class RestApi {
|
||||
|
||||
const collections = { __proto__: null }
|
||||
// add migrated collections to maintain their discoverability
|
||||
const swaggerEndpoints = ['docs', 'vms', 'hosts', 'srs']
|
||||
const swaggerEndpoints = {
|
||||
docs: {},
|
||||
vms: {
|
||||
actions: {
|
||||
start: true,
|
||||
},
|
||||
},
|
||||
hosts: {},
|
||||
srs: {},
|
||||
}
|
||||
|
||||
const withParams = (fn, paramsSchema) => {
|
||||
fn.params = paramsSchema
|
||||
@@ -1146,7 +1155,7 @@ export default class RestApi {
|
||||
api.get(
|
||||
'/',
|
||||
wrap((req, res) => {
|
||||
const endpoints = new Set([...Object.keys(collections), ...swaggerEndpoints])
|
||||
const endpoints = new Set([...Object.keys(collections), ...Object.keys(swaggerEndpoints)])
|
||||
return sendObjects(endpoints, req, res)
|
||||
})
|
||||
)
|
||||
@@ -1283,7 +1292,7 @@ export default class RestApi {
|
||||
'/:collection',
|
||||
wrap(async (req, res, next) => {
|
||||
const { collection, query } = req
|
||||
if (swaggerEndpoints.includes(collection.id)) {
|
||||
if (swaggerEndpoints[collection.id] !== undefined) {
|
||||
return next('route')
|
||||
}
|
||||
|
||||
@@ -1358,7 +1367,7 @@ export default class RestApi {
|
||||
|
||||
api.get('/:collection/:object', (req, res, next) => {
|
||||
const { collection } = req
|
||||
if (swaggerEndpoints.includes(collection.id)) {
|
||||
if (swaggerEndpoints[collection.id] !== undefined) {
|
||||
return next('route')
|
||||
}
|
||||
let result = req.object
|
||||
@@ -1522,9 +1531,10 @@ export default class RestApi {
|
||||
res.json({ ...action })
|
||||
})
|
||||
api.post('/:collection/:object/actions/:action', json(), (req, res, next) => {
|
||||
const { collection } = req
|
||||
const { action } = req.params
|
||||
const fn = req.collection.actions?.[action]
|
||||
if (fn === undefined) {
|
||||
if (fn === undefined || swaggerEndpoints[collection.id]?.actions?.[action]) {
|
||||
return next()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user