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:
parent
2b4a7c40e1
commit
bf9b53c4d9
@ -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 = {
|
||||
|
@ -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 () {
|
||||
|
@ -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')
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user