feat(vm.set): move a vm in to/out of a Self Service Group (#649)

See vatesfr/xo-web#1913
This commit is contained in:
badrAZ 2018-01-31 18:37:29 +01:00 committed by Julien Fontanet
parent 2b4a7c40e1
commit bf9b53c4d9
4 changed files with 72 additions and 27 deletions

View File

@ -1,5 +1,4 @@
import concat from 'lodash/concat'
import merge from 'lodash/merge'
import { format } from 'json-rpc-peer'
import { ignoreErrors } from 'promise-toolbox'
import {
@ -360,15 +359,7 @@ async function delete_ ({
// Update resource sets
const resourceSet = xapi.xo.getData(vm._xapiId, 'resourceSet')
if (resourceSet != null) {
const resourceSetUsage = this.computeVmResourcesUsage(vm)
const ipPoolsUsage = await this.computeVmIpPoolsUsage(vm)
ignoreErrors.call(
this.releaseLimitsInResourceSet(
merge(resourceSetUsage, ipPoolsUsage),
resourceSet
)
)
this.setVmResourceSet(vm._xapiId, null)::ignoreErrors()
}
return xapi.deleteVm(vm._xapiId, deleteDisks, force)
@ -504,11 +495,22 @@ migrate.resolve = {
// -------------------------------------------------------------------
export function set (params) {
export async function set (params) {
const VM = extract(params, 'VM')
const xapi = this.getXapi(VM)
const vmId = VM._xapiId
return xapi.editVm(VM._xapiId, params, async (limits, vm) => {
const resourceSetId = extract(params, 'resourceSet')
if (resourceSetId !== undefined) {
if (this.user.permission !== 'admin') {
throw unauthorized()
}
await this.setVmResourceSet(vmId, resourceSetId)
}
return xapi.editVm(vmId, params, async (limits, vm) => {
const resourceSet = xapi.xo.getData(vm, 'resourceSet')
if (resourceSet) {
@ -576,6 +578,9 @@ set.params = {
videoram: { type: ['string', 'number'], optional: true },
coresPerSocket: { type: ['string', 'number', 'null'], optional: true },
// Move the vm In to/Out of Self Service
resourceSet: { type: ['string', 'null'], optional: true },
}
set.resolve = {

View File

@ -1,4 +1,5 @@
import checkAuthorization from 'xo-acl-resolver'
import { forEach, includes, map } from 'lodash'
import {
ModelAlreadyExists,
@ -8,9 +9,6 @@ import {
} from '../models/acl'
import {
createRawObject,
forEach,
includes,
mapToArray,
} from '../utils'
// ===================================================================
@ -59,7 +57,7 @@ export default class {
push.apply(acls, entries)
})(acls.push)
await Promise.all(mapToArray(
await Promise.all(map(
subjects,
subject => this.getAclsForSubject(subject).then(pushAcls)
))
@ -133,6 +131,11 @@ export default class {
)
}
async removeAclsForObject (objectId) {
const acls = this._acls
await acls.remove(map(await acls.get({ object: objectId }), 'id'))
}
// -----------------------------------------------------------------
async _getPermissionsByRole () {

View File

@ -1,20 +1,24 @@
import every from 'lodash/every'
import keyBy from 'lodash/keyBy'
import remove from 'lodash/remove'
import some from 'lodash/some'
import synchronized from 'decorator-synchronized'
import {
assign,
every,
forEach,
isObject,
keyBy,
map as mapToArray,
remove,
some,
} from 'lodash'
import {
noSuchObject,
unauthorized,
} from 'xo-common/api-errors'
import {
forEach,
asyncMap,
generateUnsecureToken,
isObject,
lightSet,
map,
mapToArray,
streamToArray,
} from '../utils'
@ -124,9 +128,12 @@ export default class {
}
}
computeVmResourcesUsage (vm) {
return computeVmResourcesUsage(
async computeVmResourcesUsage (vm) {
return assign(
computeVmResourcesUsage(
this._xo.getXapi(vm).getObject(vm._xapiId)
),
await this._xo.computeVmIpPoolsUsage(vm)
)
}
@ -344,4 +351,34 @@ export default class {
await Promise.all(mapToArray(sets, set => this._save(set)))
}
async setVmResourceSet (vmId, resourceSetId) {
const xapi = this._xo.getXapi(vmId)
const previousResourceSetId = xapi.xo.getData(vmId, 'resourceSet')
if (resourceSetId === previousResourceSetId || (previousResourceSetId === undefined && resourceSetId === null)) {
return
}
const resourcesUsage = await this.computeVmResourcesUsage(this._xo.getObject(vmId))
if (resourceSetId != null) {
await this.allocateLimitsInResourceSet(resourcesUsage, resourceSetId)
}
if (previousResourceSetId !== undefined) {
await this.releaseLimitsInResourceSet(resourcesUsage, previousResourceSetId)
}
await xapi.xo.setData(vmId, 'resourceSet', resourceSetId === undefined ? null : resourceSetId)
if (previousResourceSetId !== undefined) {
await this._xo.removeAclsForObject(vmId)
}
if (resourceSetId != null) {
const { subjects } = await this.getResourceSet(resourceSetId)
await asyncMap(subjects, subject =>
this._xo.addAcl(subject, vmId, 'admin')
)
}
}
}

View File

@ -311,7 +311,7 @@ export default class {
await xapi._updateObjectMapProperty(
xapi.getObject(id),
'other_config',
{ [`xo:${camelToSnakeCase(key)}`]: JSON.stringify(value) }
{ [`xo:${camelToSnakeCase(key)}`]: value !== null ? JSON.stringify(value) : value }
)
// Register the updated object.