Files
xen-orchestra/packages/xo-server/src/api/disk.js
2019-05-14 10:21:43 +02:00

168 lines
4.0 KiB
JavaScript

import createLogger from '@xen-orchestra/log'
import pump from 'pump'
import { format, JsonRpcError } from 'json-rpc-peer'
import { noSuchObject } from 'xo-common/api-errors'
import { parseSize } from '../utils'
const log = createLogger('xo:disk')
// ===================================================================
export async function create({ name, size, sr, vm, bootable, position, mode }) {
const attach = vm !== undefined
do {
let resourceSet
if (attach && (resourceSet = vm.resourceSet) != null) {
try {
await this.checkResourceSetConstraints(resourceSet, this.user.id, [
sr.id,
])
await this.allocateLimitsInResourceSet({ disk: size }, resourceSet)
break
} catch (error) {
if (!noSuchObject.is(error, { data: { id: resourceSet } })) {
throw error
}
}
// the resource set does not exist, falls back to normal check
}
await this.checkPermissions(this.user.id, [[sr.id, 'administrate']])
} while (false)
const xapi = this.getXapi(sr)
const vdi = await xapi.createVdi({
name_label: name,
size,
sr: sr._xapiId,
})
if (attach) {
await xapi.createVbd({
bootable,
mode,
userdevice: position,
vdi: vdi.$id,
vm: vm._xapiId,
})
}
return vdi.$id
}
create.description = 'create a new disk on a SR'
create.params = {
name: { type: 'string' },
size: { type: ['integer', 'string'] },
sr: { type: 'string' },
vm: { type: 'string', optional: true },
bootable: { type: 'boolean', optional: true },
mode: { type: 'string', optional: true },
position: { type: 'string', optional: true },
}
create.resolve = {
vm: ['vm', 'VM', 'administrate'],
sr: ['sr', 'SR', false],
}
// -------------------------------------------------------------------
async function handleExportContent(req, res, { xapi, id }) {
const stream = await xapi.exportVdiContent(id)
req.on('close', () => stream.cancel())
// Remove the filename as it is already part of the URL.
stream.headers['content-disposition'] = 'attachment'
res.writeHead(
stream.statusCode,
stream.statusMessage != null ? stream.statusMessage : '',
stream.headers
)
pump(stream, res, error => {
if (error != null) {
log.warn('disk.exportContent', { error })
}
})
}
export async function exportContent({ vdi }) {
return {
$getFrom: await this.registerHttpRequest(
handleExportContent,
{
id: vdi._xapiId,
xapi: this.getXapi(vdi),
},
{
suffix: `/${encodeURIComponent(vdi.name_label)}.vhd`,
}
),
}
}
exportContent.description = 'export the content of a VDI'
exportContent.params = {
id: { type: 'string' },
}
exportContent.resolve = {
vdi: ['id', ['VDI', 'VDI-snapshot'], 'view'],
}
// -------------------------------------------------------------------
async function handleImportContent(req, res, { xapi, id }) {
// Timeout seems to be broken in Node 4.
// See https://github.com/nodejs/node/issues/3319
req.setTimeout(43200000) // 12 hours
try {
req.length = +req.headers['content-length']
await xapi.importVdiContent(id, req)
res.end(format.response(0, true))
} catch (e) {
res.writeHead(500)
res.end(format.error(0, new JsonRpcError(e.message)))
}
}
export async function importContent({ vdi }) {
return {
$sendTo: await this.registerHttpRequest(handleImportContent, {
id: vdi._xapiId,
xapi: this.getXapi(vdi),
}),
}
}
importContent.description = 'import contents into a VDI'
importContent.params = {
id: { type: 'string' },
}
importContent.resolve = {
vdi: ['id', ['VDI'], 'operate'],
}
// -------------------------------------------------------------------
export async function resize({ vdi, size }) {
await this.getXapi(vdi).resizeVdi(vdi._xapiId, parseSize(size))
}
resize.description = 'resize an existing VDI'
resize.params = {
id: { type: 'string' },
size: { type: ['integer', 'string'] },
}
resize.resolve = {
vdi: ['id', ['VDI', 'VDI-snapshot'], 'administrate'],
}