1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

F #5422: Add save action to vm datatables (#1581)

This commit is contained in:
Sergio Betanzos 2021-11-18 17:40:35 +01:00 committed by GitHub
parent 99d195b734
commit 71b92d8724
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 132 additions and 11 deletions

View File

@ -0,0 +1,21 @@
/* ------------------------------------------------------------------------- *
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
* not use this file except in compliance with the License. You may obtain *
* a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { createForm } from 'client/utils'
import { SCHEMA, FIELDS } from 'client/components/Forms/Vm/SaveAsTemplateForm/schema'
const SaveAsTemplateForm = createForm(SCHEMA, FIELDS)
export default SaveAsTemplateForm

View File

@ -0,0 +1,45 @@
/* ------------------------------------------------------------------------- *
* Copyright 2002-2021, OpenNebula Project, OpenNebula Systems *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
* not use this file except in compliance with the License. You may obtain *
* a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* ------------------------------------------------------------------------- */
import { string, boolean, object, ObjectSchema } from 'yup'
import { T, INPUT_TYPES } from 'client/constants'
import { Field, getValidationFromFields } from 'client/utils'
/** @type {Field} Template name field */
const NAME = {
name: 'name',
label: T.TemplateName,
type: INPUT_TYPES.TEXT,
validation: string()
.trim()
.required()
.default(() => undefined)
}
/** @type {Field} Persistent field */
const PERSISTENT = {
name: 'persistent',
label: T.MakeNewImagePersistent,
type: INPUT_TYPES.CHECKBOX,
validation: boolean().default(() => false),
grid: { md: 12 }
}
/** @type {Field[]} List of fields */
export const FIELDS = [NAME, PERSISTENT]
/** @type {ObjectSchema} Schema */
export const SCHEMA = object(getValidationFromFields(FIELDS))

View File

@ -23,6 +23,7 @@ import RecoverForm from 'client/components/Forms/Vm/RecoverForm'
import ResizeCapacityForm from 'client/components/Forms/Vm/ResizeCapacityForm'
import ResizeDiskForm from 'client/components/Forms/Vm/ResizeDiskForm'
import SaveAsDiskForm from 'client/components/Forms/Vm/SaveAsDiskForm'
import SaveAsTemplateForm from 'client/components/Forms/Vm/SaveAsTemplateForm'
export * from 'client/components/Forms/Vm/AttachDiskForm'
export * from 'client/components/Forms/Vm/CreateSchedActionForm'
@ -36,5 +37,6 @@ export {
RecoverForm,
ResizeCapacityForm,
ResizeDiskForm,
SaveAsDiskForm
SaveAsDiskForm,
SaveAsTemplateForm
}

View File

@ -245,7 +245,7 @@ const Actions = () => {
onSubmit: async (_, rows) => {
const ids = rows?.map?.(({ original }) => original?.ID)
await Promise.all(ids.map(id => remove(id)))
await Promise.all(ids.map(id => getVmTemplate(id)))
await getVmTemplates()
}
}]
}

View File

@ -31,10 +31,18 @@ import {
} from 'iconoir-react'
import { useAuth } from 'client/features/Auth'
import { useGeneralApi } from 'client/features/General'
import { useDatastore, useVmApi } from 'client/features/One'
import { Translate } from 'client/components/HOC'
import { RecoverForm, ChangeUserForm, ChangeGroupForm, MigrateForm } from 'client/components/Forms/Vm'
import {
RecoverForm,
ChangeUserForm,
ChangeGroupForm,
MigrateForm,
SaveAsTemplateForm
} from 'client/components/Forms/Vm'
import { createActions } from 'client/components/Tables/Enhanced/Utils'
import { PATH } from 'client/apps/sunstone/routesOne'
import { getLastHistory, isAvailableAction } from 'client/models/VirtualMachine'
@ -52,7 +60,12 @@ const ListVmNames = ({ rows = [] }) => {
const DS_NAME = datastores?.find(ds => ds?.ID === DS_ID)?.NAME ?? '--'
return (
<Typography key={`vm-${id}`} variant='inherit'>
<Typography
key={`vm-${id}`}
variant='inherit'
component='span'
display='block'
>
<Translate
word={T.WhereIsRunning}
values={[
@ -78,9 +91,11 @@ const MessageToConfirmAction = rows => (
const Actions = () => {
const history = useHistory()
const { view, getResourceView } = useAuth()
const { enqueueSuccess } = useGeneralApi()
const {
getVm,
getVms,
saveAsTemplate,
terminate,
terminateHard,
undeploy,
@ -144,7 +159,18 @@ const Actions = () => {
tooltip: T.SaveAsTemplate,
selected: { max: 1 },
icon: SaveFloppyDisk,
action: () => {}
options: [{
dialogProps: {
title: T.SaveAsTemplate,
subheader: SubHeader
},
form: SaveAsTemplateForm,
onSubmit: async (formData, rows) => {
const vmId = rows?.[0]?.original?.ID
const response = await saveAsTemplate(vmId, formData)
enqueueSuccess(response)
}
}]
},
{
tooltip: T.Manage,

View File

@ -122,7 +122,7 @@ const Cancel = props => <ActionButton action='cancel' icon={CancelIcon} {...prop
Copy.displayName = 'CopyActionButton'
Copy.propTypes = {
...ActionButton,
name: PropTypes.string.isRequired,
value: PropTypes.string
}

View File

@ -360,6 +360,8 @@ module.exports = {
/* VM schema - general */
Logo: 'Logo',
Hypervisor: 'Hypervisor',
TemplateName: 'Template name',
MakeNewImagePersistent: 'Make the new images persistent',
/* VM schema - ownership */
InstantiateAsUser: 'Instantiate as different User',
InstantiateAsGroup: 'Instantiate as different Group',
@ -402,11 +404,11 @@ module.exports = {
vCenterInstanceId: 'vCenter instance ID',
vCenterVmFolder: 'vCenter VM folder',
vCenterVmFolderConcept: `
If specified, the the VMs and Template folder path where
the VM will be created inside the data center.
The path is delimited by slashes (e.g /Management/VMs).
If no path is set the VM will be placed in the same folder where
the template is located.
If specified, the VMs and Template folder path where
the VM will be created inside the data center.
The path is delimited by slashes (e.g /Management/VMs).
If no path is set the VM will be placed in the same folder where
the template is located.
`,
/* VM Template schema - placement */
HostReqExpression: 'Host requirements expression',

View File

@ -72,6 +72,7 @@ export const changeOwnership = createAction(`${VM}/chown`, vmService.changeOwner
export const attachDisk = createAction(`${VM}/attach/disk`, vmService.attachDisk)
export const detachDisk = createAction(`${VM}/detach/disk`, vmService.detachDisk)
export const saveAsDisk = createAction(`${VM}/saveas/disk`, vmService.saveAsDisk)
export const saveAsTemplate = createAction(`${VM}/saveas/template`, vmService.saveAsTemplate)
export const resizeDisk = createAction(`${VM}/resize/disk`, vmService.resizeDisk)
export const createDiskSnapshot = createAction(`${VM}/create/disk-snapshot`, vmService.createDiskSnapshot)
export const renameDiskSnapshot = createAction(`${VM}/rename/disk-snapshot`, vmService.renameDiskSnapshot)

View File

@ -62,6 +62,7 @@ export const useVmApi = () => {
attachDisk: (id, template) => unwrapDispatch(actions.attachDisk({ id, template })),
detachDisk: (id, disk) => unwrapDispatch(actions.detachDisk({ id, disk })),
saveAsDisk: (id, data) => unwrapDispatch(actions.saveAsDisk({ id, ...data })),
saveAsTemplate: (id, data) => unwrapDispatch(actions.saveAsTemplate({ id, ...data })),
resizeDisk: (id, data) => unwrapDispatch(actions.resizeDisk({ id, ...data })),
createDiskSnapshot: (id, data) =>
unwrapDispatch(actions.createDiskSnapshot({ id, ...data })),

View File

@ -99,6 +99,29 @@ export const vmService = ({
return res?.data?.VM ?? {}
},
/**
* Clones the VM's source Template, replacing the disks with live snapshots
* of the current disks. The VM capacity and NICs are also preserved.
*
* @param {object} params - Request parameters
* @param {string|number} params.id - Virtual machine id
* @param {string} params.name - Template name
* @param {boolean} params.persistent - Make the new images persistent
* @returns {number} Virtual machine id
* @throws Fails when response isn't code 200
*/
saveAsTemplate: async ({ id, name, persistent }) => {
const res = await RestClient.request({
url: `/api/vm/save/${id}`,
method: 'POST',
data: { name, persistent }
})
if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data
return res?.data
},
/**
* Renames a virtual machine.
*