Patch upload reworked.
This commit is contained in:
parent
6e151a9f8b
commit
883a30c7ad
@ -1,109 +0,0 @@
|
|||||||
$debug = (require 'debug') 'xo:api:vm'
|
|
||||||
{$coroutine, $wait} = require '../fibers-utils'
|
|
||||||
|
|
||||||
#=====================================================================
|
|
||||||
|
|
||||||
set = $coroutine (params) ->
|
|
||||||
{pool} = params
|
|
||||||
xapi = @getXAPI pool
|
|
||||||
|
|
||||||
for param, field of {
|
|
||||||
'name_label'
|
|
||||||
'name_description'
|
|
||||||
}
|
|
||||||
continue unless param of params
|
|
||||||
|
|
||||||
$wait xapi.call "pool.set_#{field}", pool.ref, params[param]
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
set.params = {
|
|
||||||
id: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
name_label: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
name_description: {
|
|
||||||
type: 'string',
|
|
||||||
optional: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
set.resolve = {
|
|
||||||
pool: ['id', 'pool'],
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.set = set
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------
|
|
||||||
# Upload a patch and apply it
|
|
||||||
# If host is given, only apply to a host and not the whole pool
|
|
||||||
|
|
||||||
# FIXME: remove and implements uploadPatch instead
|
|
||||||
patch = $coroutine ({pool, host}) ->
|
|
||||||
xapi = @getXAPI pool
|
|
||||||
|
|
||||||
taskRef = $wait xapi.call 'task.create', 'Patch upload from XO', ''
|
|
||||||
@watchTask taskRef
|
|
||||||
.then $coroutine (patchRef) ->
|
|
||||||
$debug 'Patch upload succeeded'
|
|
||||||
if not host
|
|
||||||
xapi.call 'pool_patch.pool_apply', patchRef
|
|
||||||
else
|
|
||||||
host = @getObject host
|
|
||||||
xapi.call 'pool_patch.apply', patchRef, host.ref
|
|
||||||
return
|
|
||||||
.catch (error) ->
|
|
||||||
$debug 'Patch upload failed: %j', error
|
|
||||||
return
|
|
||||||
.finally $coroutine ->
|
|
||||||
xapi.call 'task.destroy', taskRef
|
|
||||||
return
|
|
||||||
|
|
||||||
if not host
|
|
||||||
host = @getObject pool.master, 'host'
|
|
||||||
|
|
||||||
url = $wait @registerProxyRequest {
|
|
||||||
# Receive a POST but send a PUT.
|
|
||||||
method: 'put'
|
|
||||||
proxyMethod: 'post'
|
|
||||||
hostname: host.address
|
|
||||||
pathname: '/pool_patch_upload'
|
|
||||||
query: {
|
|
||||||
session_id: xapi.sessionId
|
|
||||||
task_id: taskRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
$sendTo: url
|
|
||||||
}
|
|
||||||
|
|
||||||
patch.params = {
|
|
||||||
pool: { type: 'string' },
|
|
||||||
host: { type: 'string', optional: true },
|
|
||||||
}
|
|
||||||
|
|
||||||
patch.resolve = {
|
|
||||||
pool: ['pool', 'pool'],
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.patch = patch
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------
|
|
||||||
|
|
||||||
installPatch = $coroutine ({pool, patch: patchUuid}) ->
|
|
||||||
return @getXAPI(pool).installPoolPatchOnAllHosts(patchUuid)
|
|
||||||
|
|
||||||
installPatch.params = {
|
|
||||||
pool: { type: 'string' }
|
|
||||||
patch: { type: 'string' }
|
|
||||||
}
|
|
||||||
|
|
||||||
installPatch.resolve = {
|
|
||||||
pool: ['pool', 'pool']
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.installPatch = installPatch
|
|
75
src/api/pool.js
Normal file
75
src/api/pool.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
export async function set (params) {
|
||||||
|
const {pool} = params
|
||||||
|
delete params.pool
|
||||||
|
|
||||||
|
await this.getXAPI(pool).setPoolProperties(params)
|
||||||
|
}
|
||||||
|
|
||||||
|
set.params = {
|
||||||
|
id: {
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
name_label: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
name_description: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set.resolve = {
|
||||||
|
pool: ['id', 'pool']
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
export async function installPatch ({pool, patch: patchUuid}) {
|
||||||
|
await this.getXAPI(pool).installPoolPatchOnAllHosts(patchUuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
installPatch.params = {
|
||||||
|
pool: {
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
patch: {
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
installPatch.resolve = {
|
||||||
|
pool: ['pool', 'pool']
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
async function handlePatchUpload (req, res, {pool}) {
|
||||||
|
const {headers: {['content-length']: contentLength}} = req
|
||||||
|
if (!contentLength) {
|
||||||
|
res.writeHead(400)
|
||||||
|
res.end('Content length is mandatory')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.getXAPI(pool).uploadPoolPatch(req, contentLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function uploadPatch ({pool}) {
|
||||||
|
return {
|
||||||
|
$sendTo: await this.registerHttpRequest(handlePatchUpload, {pool})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadPatch.params = {
|
||||||
|
pool: { type: 'string' }
|
||||||
|
}
|
||||||
|
|
||||||
|
uploadPatch.resolve = {
|
||||||
|
pool: ['pool', 'pool']
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: compatibility
|
||||||
|
export {uploadPatch as patch}
|
@ -31,7 +31,7 @@ import {readFile} from 'fs-promise'
|
|||||||
import Api from './api'
|
import Api from './api'
|
||||||
import WebServer from 'http-server-plus'
|
import WebServer from 'http-server-plus'
|
||||||
import wsProxy from './ws-proxy'
|
import wsProxy from './ws-proxy'
|
||||||
import XO from './xo'
|
import Xo from './xo'
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
@ -370,7 +370,7 @@ export default async function main (args) {
|
|||||||
|
|
||||||
// Create the main object which will connects to Xen servers and
|
// Create the main object which will connects to Xen servers and
|
||||||
// manages all the models.
|
// manages all the models.
|
||||||
const xo = new XO()
|
const xo = new Xo()
|
||||||
await xo.start({
|
await xo.start({
|
||||||
redis: {
|
redis: {
|
||||||
uri: config.redis && config.redis.uri
|
uri: config.redis && config.redis.uri
|
||||||
@ -393,7 +393,7 @@ export default async function main (args) {
|
|||||||
setUpConsoleProxy(webServer, xo)
|
setUpConsoleProxy(webServer, xo)
|
||||||
|
|
||||||
// Must be set up before the API.
|
// Must be set up before the API.
|
||||||
connect.use(bind(xo.handleProxyRequest, xo))
|
connect.use(bind(xo._handleProxyRequest, xo))
|
||||||
|
|
||||||
// Must be set up before the static files.
|
// Must be set up before the static files.
|
||||||
setUpApi(webServer, xo)
|
setUpApi(webServer, xo)
|
||||||
|
@ -327,7 +327,7 @@ export default class Xapi extends XapiBase {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
async _uploadPoolPatch (stream, length) {
|
async uploadPoolPatch (stream, length) {
|
||||||
const task = await this._createTask('Patch upload from XO')
|
const task = await this._createTask('Patch upload from XO')
|
||||||
|
|
||||||
// TODO: Update when xen-api >= 0.5
|
// TODO: Update when xen-api >= 0.5
|
||||||
@ -378,7 +378,7 @@ export default class Xapi extends XapiBase {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const length = await eventToPromise(proxy, 'length')
|
const length = await eventToPromise(proxy, 'length')
|
||||||
return this._uploadPoolPatch(proxy, length)
|
return this.uploadPoolPatch(proxy, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
async installPoolPatchOnHost (patchUuid, hostId) {
|
async installPoolPatchOnHost (patchUuid, hostId) {
|
||||||
|
80
src/xo.js
80
src/xo.js
@ -422,28 +422,59 @@ export default class Xo extends EventEmitter {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
async registerProxyRequest (opts) {
|
_handleHttpRequest (req, res, next) {
|
||||||
if (isString(opts)) {
|
const {url} = req
|
||||||
opts = parseUrl(opts)
|
|
||||||
} else {
|
|
||||||
opts.method = opts.method != null ?
|
|
||||||
opts.method.toUpperCase() :
|
|
||||||
'GET'
|
|
||||||
|
|
||||||
opts.proxyMethod = opts.proxyMethod != null ?
|
const {_httpRequestWatchers: watchers} = this
|
||||||
opts.proxyMethod.toUpperCase() :
|
const watcher = watchers[url]
|
||||||
opts.method
|
if (!watcher) {
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete watchers[url]
|
||||||
|
|
||||||
|
const {fn, data} = watcher
|
||||||
|
Bluebird.try(watcher, [data]).then(
|
||||||
|
result => {
|
||||||
|
if (result != null) {
|
||||||
|
res.end(JSON.stringify(result))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
console.error('HTTP request error', error)
|
||||||
|
|
||||||
|
if (!res.headersSent) {
|
||||||
|
res.writeHead(500)
|
||||||
|
}
|
||||||
|
res.end('unknown error')
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.createdAt = Date.now()
|
async registerHttpRequest (fn, data) {
|
||||||
|
const {_httpRequestWatchers: watchers} = this
|
||||||
|
|
||||||
const url = `/${await generateToken()} `
|
const url = await (function generateUniqueUrl () {
|
||||||
this._proxyRequests[url] = opts
|
return generateToken().then(token => {
|
||||||
|
const url = `/api/${token}`
|
||||||
|
|
||||||
|
return url in watchers ?
|
||||||
|
generateUrl() :
|
||||||
|
url
|
||||||
|
})
|
||||||
|
})()
|
||||||
|
|
||||||
|
watchers[url] = {
|
||||||
|
fn,
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
handleProxyRequest (req, res, next) {
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
|
_handleProxyRequest (req, res, next) {
|
||||||
const {url} = req
|
const {url} = req
|
||||||
const request = this._proxyRequests[url]
|
const request = this._proxyRequests[url]
|
||||||
if (!request || req.method !== request.proxyMethod) {
|
if (!request || req.method !== request.proxyMethod) {
|
||||||
@ -482,6 +513,27 @@ export default class Xo extends EventEmitter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async registerProxyRequest (opts) {
|
||||||
|
if (isString(opts)) {
|
||||||
|
opts = parseUrl(opts)
|
||||||
|
} else {
|
||||||
|
opts.method = opts.method != null ?
|
||||||
|
opts.method.toUpperCase() :
|
||||||
|
'GET'
|
||||||
|
|
||||||
|
opts.proxyMethod = opts.proxyMethod != null ?
|
||||||
|
opts.proxyMethod.toUpperCase() :
|
||||||
|
opts.method
|
||||||
|
}
|
||||||
|
|
||||||
|
opts.createdAt = Date.now()
|
||||||
|
|
||||||
|
const url = `/${await generateToken()} `
|
||||||
|
this._proxyRequests[url] = opts
|
||||||
|
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
||||||
watchTask (ref) {
|
watchTask (ref) {
|
||||||
|
Loading…
Reference in New Issue
Block a user