mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-22 18:50:08 +03:00
parent
99d195b734
commit
71b92d8724
@ -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
|
@ -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))
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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 })),
|
||||
|
@ -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.
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user