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 concat from 'lodash/concat'
|
||||||
import merge from 'lodash/merge'
|
|
||||||
import { format } from 'json-rpc-peer'
|
import { format } from 'json-rpc-peer'
|
||||||
import { ignoreErrors } from 'promise-toolbox'
|
import { ignoreErrors } from 'promise-toolbox'
|
||||||
import {
|
import {
|
||||||
@ -360,15 +359,7 @@ async function delete_ ({
|
|||||||
// Update resource sets
|
// Update resource sets
|
||||||
const resourceSet = xapi.xo.getData(vm._xapiId, 'resourceSet')
|
const resourceSet = xapi.xo.getData(vm._xapiId, 'resourceSet')
|
||||||
if (resourceSet != null) {
|
if (resourceSet != null) {
|
||||||
const resourceSetUsage = this.computeVmResourcesUsage(vm)
|
this.setVmResourceSet(vm._xapiId, null)::ignoreErrors()
|
||||||
const ipPoolsUsage = await this.computeVmIpPoolsUsage(vm)
|
|
||||||
|
|
||||||
ignoreErrors.call(
|
|
||||||
this.releaseLimitsInResourceSet(
|
|
||||||
merge(resourceSetUsage, ipPoolsUsage),
|
|
||||||
resourceSet
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return xapi.deleteVm(vm._xapiId, deleteDisks, force)
|
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 VM = extract(params, 'VM')
|
||||||
const xapi = this.getXapi(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')
|
const resourceSet = xapi.xo.getData(vm, 'resourceSet')
|
||||||
|
|
||||||
if (resourceSet) {
|
if (resourceSet) {
|
||||||
@ -576,6 +578,9 @@ set.params = {
|
|||||||
videoram: { type: ['string', 'number'], optional: true },
|
videoram: { type: ['string', 'number'], optional: true },
|
||||||
|
|
||||||
coresPerSocket: { type: ['string', 'number', 'null'], 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 = {
|
set.resolve = {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import checkAuthorization from 'xo-acl-resolver'
|
import checkAuthorization from 'xo-acl-resolver'
|
||||||
|
import { forEach, includes, map } from 'lodash'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ModelAlreadyExists,
|
ModelAlreadyExists,
|
||||||
@ -8,9 +9,6 @@ import {
|
|||||||
} from '../models/acl'
|
} from '../models/acl'
|
||||||
import {
|
import {
|
||||||
createRawObject,
|
createRawObject,
|
||||||
forEach,
|
|
||||||
includes,
|
|
||||||
mapToArray,
|
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
@ -59,7 +57,7 @@ export default class {
|
|||||||
push.apply(acls, entries)
|
push.apply(acls, entries)
|
||||||
})(acls.push)
|
})(acls.push)
|
||||||
|
|
||||||
await Promise.all(mapToArray(
|
await Promise.all(map(
|
||||||
subjects,
|
subjects,
|
||||||
subject => this.getAclsForSubject(subject).then(pushAcls)
|
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 () {
|
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 synchronized from 'decorator-synchronized'
|
||||||
|
import {
|
||||||
|
assign,
|
||||||
|
every,
|
||||||
|
forEach,
|
||||||
|
isObject,
|
||||||
|
keyBy,
|
||||||
|
map as mapToArray,
|
||||||
|
remove,
|
||||||
|
some,
|
||||||
|
} from 'lodash'
|
||||||
import {
|
import {
|
||||||
noSuchObject,
|
noSuchObject,
|
||||||
unauthorized,
|
unauthorized,
|
||||||
} from 'xo-common/api-errors'
|
} from 'xo-common/api-errors'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
forEach,
|
asyncMap,
|
||||||
generateUnsecureToken,
|
generateUnsecureToken,
|
||||||
isObject,
|
|
||||||
lightSet,
|
lightSet,
|
||||||
map,
|
map,
|
||||||
mapToArray,
|
|
||||||
streamToArray,
|
streamToArray,
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
|
|
||||||
@ -124,9 +128,12 @@ export default class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
computeVmResourcesUsage (vm) {
|
async computeVmResourcesUsage (vm) {
|
||||||
return computeVmResourcesUsage(
|
return assign(
|
||||||
this._xo.getXapi(vm).getObject(vm._xapiId)
|
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)))
|
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(
|
await xapi._updateObjectMapProperty(
|
||||||
xapi.getObject(id),
|
xapi.getObject(id),
|
||||||
'other_config',
|
'other_config',
|
||||||
{ [`xo:${camelToSnakeCase(key)}`]: JSON.stringify(value) }
|
{ [`xo:${camelToSnakeCase(key)}`]: value !== null ? JSON.stringify(value) : value }
|
||||||
)
|
)
|
||||||
|
|
||||||
// Register the updated object.
|
// Register the updated object.
|
||||||
|
Loading…
Reference in New Issue
Block a user