parent
8b05486945
commit
8971d218bb
@ -500,7 +500,6 @@ export async function set (params) {
|
|||||||
const vmId = VM._xapiId
|
const vmId = VM._xapiId
|
||||||
|
|
||||||
const resourceSetId = extract(params, 'resourceSet')
|
const resourceSetId = extract(params, 'resourceSet')
|
||||||
|
|
||||||
if (resourceSetId !== undefined) {
|
if (resourceSetId !== undefined) {
|
||||||
if (this.user.permission !== 'admin') {
|
if (this.user.permission !== 'admin') {
|
||||||
throw unauthorized()
|
throw unauthorized()
|
||||||
@ -509,6 +508,11 @@ export async function set (params) {
|
|||||||
await this.setVmResourceSet(vmId, resourceSetId)
|
await this.setVmResourceSet(vmId, resourceSetId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const share = extract(params, 'share')
|
||||||
|
if (share) {
|
||||||
|
await this.shareVmResourceSet(vmId)
|
||||||
|
}
|
||||||
|
|
||||||
return xapi.editVm(vmId, params, async (limits, vm) => {
|
return xapi.editVm(vmId, params, async (limits, vm) => {
|
||||||
const resourceSet = xapi.xo.getData(vm, 'resourceSet')
|
const resourceSet = xapi.xo.getData(vm, 'resourceSet')
|
||||||
|
|
||||||
@ -580,6 +584,8 @@ set.params = {
|
|||||||
|
|
||||||
// Move the vm In to/Out of Self Service
|
// Move the vm In to/Out of Self Service
|
||||||
resourceSet: { type: ['string', 'null'], optional: true },
|
resourceSet: { type: ['string', 'null'], optional: true },
|
||||||
|
|
||||||
|
share: { type: 'boolean', optional: true },
|
||||||
}
|
}
|
||||||
|
|
||||||
set.resolve = {
|
set.resolve = {
|
||||||
|
@ -391,10 +391,18 @@ export default class {
|
|||||||
await this._xo.removeAclsForObject(vmId)
|
await this._xo.removeAclsForObject(vmId)
|
||||||
}
|
}
|
||||||
if (resourceSetId != null) {
|
if (resourceSetId != null) {
|
||||||
const { subjects } = await this.getResourceSet(resourceSetId)
|
await this.shareVmResourceSet(vmId)
|
||||||
await asyncMap(subjects, subject =>
|
|
||||||
this._xo.addAcl(subject, vmId, 'admin')
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async shareVmResourceSet (vmId) {
|
||||||
|
const xapi = this._xo.getXapi(vmId)
|
||||||
|
const resourceSetId = xapi.xo.getData(vmId, 'resourceSet')
|
||||||
|
if (resourceSetId === undefined) {
|
||||||
|
throw new Error('the vm is not in a resource set')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { subjects } = await this.getResourceSet(resourceSetId)
|
||||||
|
await asyncMap(subjects, subject => this._xo.addAcl(subject, vmId, 'admin'))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -844,6 +844,7 @@ const messages = {
|
|||||||
// ----- VM advanced tab -----
|
// ----- VM advanced tab -----
|
||||||
vmRemoveButton: 'Remove',
|
vmRemoveButton: 'Remove',
|
||||||
vmConvertButton: 'Convert',
|
vmConvertButton: 'Convert',
|
||||||
|
vmShareButton: 'Share',
|
||||||
xenSettingsLabel: 'Xen settings',
|
xenSettingsLabel: 'Xen settings',
|
||||||
guestOsLabel: 'Guest OS',
|
guestOsLabel: 'Guest OS',
|
||||||
miscLabel: 'Misc',
|
miscLabel: 'Misc',
|
||||||
@ -1252,6 +1253,9 @@ const messages = {
|
|||||||
deleteRemotesModalMessage:
|
deleteRemotesModalMessage:
|
||||||
'Are you sure you want to delete {nRemotes, number} remote{nRemotes, plural, one {} other {s}}?',
|
'Are you sure you want to delete {nRemotes, number} remote{nRemotes, plural, one {} other {s}}?',
|
||||||
revertVmModalTitle: 'Revert your VM',
|
revertVmModalTitle: 'Revert your VM',
|
||||||
|
shareVmInResourceSetModalTitle: 'Share your VM',
|
||||||
|
shareVmInResourceSetModalMessage:
|
||||||
|
'This VM will be shared with all the members of the self-service {self}. Are you sure?',
|
||||||
deleteVifsModalTitle: 'Delete VIF{nVifs, plural, one {} other {s}}',
|
deleteVifsModalTitle: 'Delete VIF{nVifs, plural, one {} other {s}}',
|
||||||
deleteVifsModalMessage:
|
deleteVifsModalMessage:
|
||||||
'Are you sure you want to delete {nVifs, number} VIF{nVifs, plural, one {} other {s}}?',
|
'Are you sure you want to delete {nVifs, number} VIF{nVifs, plural, one {} other {s}}?',
|
||||||
|
@ -24,6 +24,7 @@ import { forbiddenOperation, noHostsAvailable } from 'xo-common/api-errors'
|
|||||||
import _ from '../intl'
|
import _ from '../intl'
|
||||||
import invoke from '../invoke'
|
import invoke from '../invoke'
|
||||||
import logError from '../log-error'
|
import logError from '../log-error'
|
||||||
|
import renderXoItem from '../render-xo-item'
|
||||||
import store from 'store'
|
import store from 'store'
|
||||||
import { alert, chooseAction, confirm } from '../modal'
|
import { alert, chooseAction, confirm } from '../modal'
|
||||||
import { error, info, success } from '../notification'
|
import { error, info, success } from '../notification'
|
||||||
@ -1171,6 +1172,14 @@ export const createVgpu = (vm, { gpuGroup, vgpuType }) =>
|
|||||||
|
|
||||||
export const deleteVgpu = vgpu => _call('vm.deleteVgpu', resolveIds({ vgpu }))
|
export const deleteVgpu = vgpu => _call('vm.deleteVgpu', resolveIds({ vgpu }))
|
||||||
|
|
||||||
|
export const shareVm = (vm, resourceSet) =>
|
||||||
|
confirm({
|
||||||
|
title: _('shareVmInResourceSetModalTitle'),
|
||||||
|
body: _('shareVmInResourceSetModalMessage', {
|
||||||
|
self: renderXoItem(resourceSet),
|
||||||
|
}),
|
||||||
|
}).then(() => editVm(vm, { share: true }), noop)
|
||||||
|
|
||||||
// DISK ---------------------------------------------------------------
|
// DISK ---------------------------------------------------------------
|
||||||
|
|
||||||
export const createDisk = (name, size, sr, { vm, bootable, mode, position }) =>
|
export const createDisk = (name, size, sr, { vm, bootable, mode, position }) =>
|
||||||
|
@ -356,6 +356,10 @@
|
|||||||
@extend .text-primary;
|
@extend .text-primary;
|
||||||
@extend .fa-ship;
|
@extend .fa-ship;
|
||||||
}
|
}
|
||||||
|
&-share {
|
||||||
|
@extend .fa;
|
||||||
|
@extend .fa-list-alt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic states
|
// Generic states
|
||||||
|
@ -24,9 +24,9 @@ import {
|
|||||||
osFamily,
|
osFamily,
|
||||||
} from 'utils'
|
} from 'utils'
|
||||||
import {
|
import {
|
||||||
createVgpu,
|
|
||||||
cloneVm,
|
cloneVm,
|
||||||
convertVmToTemplate,
|
convertVmToTemplate,
|
||||||
|
createVgpu,
|
||||||
deleteVgpu,
|
deleteVgpu,
|
||||||
deleteVm,
|
deleteVm,
|
||||||
editVm,
|
editVm,
|
||||||
@ -34,6 +34,7 @@ import {
|
|||||||
recoveryStartVm,
|
recoveryStartVm,
|
||||||
restartVm,
|
restartVm,
|
||||||
resumeVm,
|
resumeVm,
|
||||||
|
shareVm,
|
||||||
stopVm,
|
stopVm,
|
||||||
subscribeResourceSets,
|
subscribeResourceSets,
|
||||||
suspendVm,
|
suspendVm,
|
||||||
@ -41,7 +42,12 @@ import {
|
|||||||
XEN_DEFAULT_CPU_WEIGHT,
|
XEN_DEFAULT_CPU_WEIGHT,
|
||||||
XEN_VIDEORAM_VALUES,
|
XEN_VIDEORAM_VALUES,
|
||||||
} from 'xo'
|
} from 'xo'
|
||||||
import { createGetObjectsOfType, createSelector, isAdmin } from 'selectors'
|
import {
|
||||||
|
createGetObjectsOfType,
|
||||||
|
createSelector,
|
||||||
|
getCheckPermissions,
|
||||||
|
isAdmin,
|
||||||
|
} from 'selectors'
|
||||||
|
|
||||||
const forceReboot = vm => restartVm(vm, true)
|
const forceReboot = vm => restartVm(vm, true)
|
||||||
const forceShutdown = vm => stopVm(vm, true)
|
const forceShutdown = vm => stopVm(vm, true)
|
||||||
@ -122,6 +128,31 @@ class ResourceSetItem extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@addSubscriptions({
|
||||||
|
resourceSets: subscribeResourceSets,
|
||||||
|
})
|
||||||
|
class ShareVmButton extends Component {
|
||||||
|
_shareVm = () => {
|
||||||
|
const { resourceSets, vm } = this.props
|
||||||
|
|
||||||
|
return shareVm(vm, {
|
||||||
|
...find(resourceSets, { id: vm.resourceSet }),
|
||||||
|
type: 'resourceSet',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<TabButton
|
||||||
|
btnStyle='primary'
|
||||||
|
handler={this._shareVm}
|
||||||
|
icon='vm-share'
|
||||||
|
labelId='vmShareButton'
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class NewVgpu extends Component {
|
class NewVgpu extends Component {
|
||||||
get value () {
|
get value () {
|
||||||
return this.state
|
return this.state
|
||||||
@ -284,16 +315,26 @@ export default connectStore(() => {
|
|||||||
createSelector(getVgpus, vgpus => map(vgpus, 'gpuGroup'))
|
createSelector(getVgpus, vgpus => map(vgpus, 'gpuGroup'))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const getCanAdministrate = createSelector(
|
||||||
|
getCheckPermissions,
|
||||||
|
(_, props) => props.vm.id,
|
||||||
|
(check, id) => check(id, 'administrate')
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
canAdministrate: getCanAdministrate,
|
||||||
gpuGroup: getGpuGroup,
|
gpuGroup: getGpuGroup,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
vgpus: getVgpus,
|
vgpus: getVgpus,
|
||||||
vgpuTypes: getVgpuTypes,
|
vgpuTypes: getVgpuTypes,
|
||||||
}
|
}
|
||||||
})(({ container, gpuGroup, isAdmin, vgpus, vgpuTypes, vm }) => (
|
})(
|
||||||
|
({ canAdministrate, container, gpuGroup, isAdmin, vgpus, vgpuTypes, vm }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<Row>
|
<Row>
|
||||||
<Col className='text-xs-right'>
|
<Col className='text-xs-right'>
|
||||||
|
{(isAdmin || canAdministrate) &&
|
||||||
|
vm.resourceSet != null && <ShareVmButton vm={vm} />}
|
||||||
{vm.power_state === 'Running' && (
|
{vm.power_state === 'Running' && (
|
||||||
<span>
|
<span>
|
||||||
<TabButton
|
<TabButton
|
||||||
@ -578,7 +619,8 @@ export default connectStore(() => {
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{_('osKernel')}</th>
|
<th>{_('osKernel')}</th>
|
||||||
<td>
|
<td>
|
||||||
{(vm.os_version && vm.os_version.uname) || _('unknownOsKernel')}
|
{(vm.os_version && vm.os_version.uname) ||
|
||||||
|
_('unknownOsKernel')}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -620,4 +662,5 @@ export default connectStore(() => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Container>
|
</Container>
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user