mirror of
https://github.com/OpenNebula/one.git
synced 2025-03-16 22:50:10 +03:00
F OpenNebula/one#5422: Add resize vm dialog (#1385)
This commit is contained in:
parent
c5d3bc82fa
commit
8d2a0a29b1
@ -92,7 +92,7 @@ const DialogForm = memo(
|
||||
}
|
||||
)
|
||||
|
||||
DialogForm.propTypes = {
|
||||
export const DialogFormPropTypes = {
|
||||
open: PropTypes.bool.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
values: PropTypes.oneOfType([
|
||||
@ -109,6 +109,8 @@ DialogForm.propTypes = {
|
||||
])
|
||||
}
|
||||
|
||||
DialogForm.propTypes = DialogFormPropTypes
|
||||
|
||||
DialogForm.defaultProps = {
|
||||
open: true,
|
||||
title: 'Title dialog form',
|
||||
|
@ -13,12 +13,13 @@
|
||||
* See the License for the specific language governing permissions and *
|
||||
* limitations under the License. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
import DialogForm from 'client/components/Dialogs/DialogForm'
|
||||
import DialogForm, { DialogFormPropTypes } from 'client/components/Dialogs/DialogForm'
|
||||
import DialogRequest from 'client/components/Dialogs/DialogRequest'
|
||||
import DialogConfirmation from 'client/components/Dialogs/DialogConfirmation'
|
||||
|
||||
export {
|
||||
DialogForm,
|
||||
DialogFormPropTypes,
|
||||
DialogRequest,
|
||||
DialogConfirmation
|
||||
}
|
||||
|
80
src/fireedge/src/client/components/Tabs/Vm/Capacity/index.js
Normal file
80
src/fireedge/src/client/components/Tabs/Vm/Capacity/index.js
Normal file
@ -0,0 +1,80 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import * as React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { useVmApi } from 'client/features/One'
|
||||
import { useDialog } from 'client/hooks'
|
||||
import { TabContext } from 'client/components/Tabs/TabProvider'
|
||||
import { DialogForm } from 'client/components/Dialogs'
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
import { SCHEMA, FIELDS } from 'client/formSchema/Vm/resize'
|
||||
|
||||
import InformationPanel from 'client/components/Tabs/Vm/Capacity/information'
|
||||
|
||||
import * as VirtualMachine from 'client/models/VirtualMachine'
|
||||
import * as Helper from 'client/models/Helper'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
const VmCapacityTab = ({ tabProps: { actions = [] } = {} }) => {
|
||||
const { display, show, hide } = useDialog()
|
||||
const { resize } = useVmApi()
|
||||
|
||||
const { handleRefetch, data: vm = {} } = React.useContext(TabContext)
|
||||
const { ID, TEMPLATE } = vm
|
||||
|
||||
const hypervisor = VirtualMachine.getHypervisor(vm)
|
||||
const actionsAvailable = Helper.getActionsAvailable(actions, hypervisor)
|
||||
|
||||
const handleResize = async formData => {
|
||||
const { enforce, ...restOfData } = formData
|
||||
const template = Helper.jsonToXml({ ROOT: restOfData })
|
||||
|
||||
const response = await resize(ID, { enforce, template })
|
||||
String(response) === String(ID) && await handleRefetch?.()
|
||||
hide()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<InformationPanel
|
||||
actions={actionsAvailable}
|
||||
handleOpenResizeDialog={show}
|
||||
vm={vm}
|
||||
/>
|
||||
{display && (
|
||||
<DialogForm
|
||||
title={`${T.ResizeCapacity}`}
|
||||
resolver={() => SCHEMA}
|
||||
values={SCHEMA.cast(TEMPLATE, { stripUnknown: true })}
|
||||
onCancel={hide}
|
||||
onSubmit={handleResize}
|
||||
>
|
||||
<FormWithSchema cy='form-dg-vm-resize' fields={FIELDS} />
|
||||
</DialogForm>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
VmCapacityTab.propTypes = {
|
||||
tabProps: PropTypes.object
|
||||
}
|
||||
|
||||
VmCapacityTab.displayName = 'VmCapacityTab'
|
||||
|
||||
export default VmCapacityTab
|
@ -18,14 +18,10 @@ import * as React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { makeStyles, Paper, Typography, Button } from '@material-ui/core'
|
||||
|
||||
import { useDialog } from 'client/hooks'
|
||||
import { TabContext } from 'client/components/Tabs/TabProvider'
|
||||
import { DialogConfirmation } from 'client/components/Dialogs'
|
||||
import { Tr } from 'client/components/HOC'
|
||||
|
||||
import { prettyBytes } from 'client/utils'
|
||||
import * as VirtualMachine from 'client/models/VirtualMachine'
|
||||
import * as Helper from 'client/models/Helper'
|
||||
import { prettyBytes } from 'client/utils'
|
||||
import { T, VM_ACTIONS } from 'client/constants'
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
@ -63,16 +59,11 @@ const useStyles = makeStyles(theme => ({
|
||||
}
|
||||
}))
|
||||
|
||||
const VmCapacityTab = ({ tabProps: { actions = [] } = {} }) => {
|
||||
const InformationPanel = ({ actions, vm = {}, handleOpenResizeDialog }) => {
|
||||
const classes = useStyles()
|
||||
const { display, show, hide } = useDialog()
|
||||
|
||||
const { data: vm = {} } = React.useContext(TabContext)
|
||||
const { TEMPLATE } = vm
|
||||
|
||||
const isVCenter = VirtualMachine.isVCenter(vm)
|
||||
const hypervisor = VirtualMachine.getHypervisor(vm)
|
||||
const actionsAvailable = Helper.getActionsAvailable(actions, hypervisor)
|
||||
|
||||
const capacity = [
|
||||
{
|
||||
@ -109,12 +100,12 @@ const VmCapacityTab = ({ tabProps: { actions = [] } = {} }) => {
|
||||
return (
|
||||
<Paper variant='outlined' className={classes.root}>
|
||||
<div className={classes.actions}>
|
||||
{actionsAvailable?.includes?.(VM_ACTIONS.RESIZE_CAPACITY) && (
|
||||
{actions?.includes?.(VM_ACTIONS.RESIZE_CAPACITY) && (
|
||||
<Button
|
||||
data-cy='resize'
|
||||
size='small'
|
||||
color='secondary'
|
||||
onClick={show}
|
||||
onClick={handleOpenResizeDialog}
|
||||
variant='contained'
|
||||
>
|
||||
{Tr(T.Resize)}
|
||||
@ -131,24 +122,16 @@ const VmCapacityTab = ({ tabProps: { actions = [] } = {} }) => {
|
||||
</Typography>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{display && (
|
||||
<DialogConfirmation
|
||||
title={T.ResizeCapacity}
|
||||
handleAccept={hide}
|
||||
handleCancel={hide}
|
||||
>
|
||||
<p>TODO: should define in view yaml ??</p>
|
||||
</DialogConfirmation>
|
||||
)}
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
VmCapacityTab.propTypes = {
|
||||
tabProps: PropTypes.object
|
||||
InformationPanel.propTypes = {
|
||||
handleOpenResizeDialog: PropTypes.function,
|
||||
actions: PropTypes.array,
|
||||
vm: PropTypes.object
|
||||
}
|
||||
|
||||
VmCapacityTab.displayName = 'VmCapacityTab'
|
||||
InformationPanel.displayName = 'InformationPanel'
|
||||
|
||||
export default VmCapacityTab
|
||||
export default InformationPanel
|
@ -45,7 +45,7 @@ const VmInfoTab = ({ tabProps = {} }) => {
|
||||
} = tabProps
|
||||
|
||||
const { changeOwnership, changePermissions, rename, updateUserTemplate } = useVmApi()
|
||||
const { handleRefetch, data: vm } = React.useContext(TabContext)
|
||||
const { handleRefetch, data: vm = {} } = React.useContext(TabContext)
|
||||
const { ID, UNAME, UID, GNAME, GID, PERMISSIONS, USER_TEMPLATE, MONITORING } = vm
|
||||
|
||||
const handleChangeOwnership = async newOwnership => {
|
||||
|
@ -42,6 +42,7 @@ export const terminateVm = createAction(
|
||||
|
||||
export const updateUserTemplate = createAction('vm/update', vmService.updateUserTemplate)
|
||||
export const rename = createAction('vm/rename', vmService.rename)
|
||||
export const resize = createAction('vm/resize', vmService.resize)
|
||||
export const changePermissions = createAction('vm/chmod', vmService.changePermissions)
|
||||
export const changeOwnership = createAction('vm/chown', vmService.changeOwnership)
|
||||
export const detachNic = createAction('vm/detach/nic', vmService.detachNic)
|
||||
|
@ -39,6 +39,7 @@ export const useVmApi = () => {
|
||||
updateUserTemplate: (id, template, replace) =>
|
||||
unwrapDispatch(actions.updateUserTemplate({ id, template, replace })),
|
||||
rename: (id, name) => unwrapDispatch(actions.rename({ id, name })),
|
||||
resize: (id, data) => unwrapDispatch(actions.resize({ id, ...data })),
|
||||
changePermissions: (id, permissions) =>
|
||||
unwrapDispatch(actions.changePermissions({ id, permissions })),
|
||||
changeOwnership: (id, ownership) =>
|
||||
|
@ -120,6 +120,29 @@ export const vmService = ({
|
||||
return res?.data
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the capacity of the virtual machine.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {string|number} params.id - Virtual machine id
|
||||
* @param {string} params.template - Template containing the new capacity
|
||||
* @param {boolean} params.enforce
|
||||
* - `true` to enforce the Host capacity isn't over committed.
|
||||
* @returns {number} Virtual machine id
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
resize: async ({ id, template, enforce }) => {
|
||||
const name = Actions.VM_RESIZE
|
||||
const command = { name, ...Commands[name] }
|
||||
const config = requestConfig({ id, template, enforce }, command)
|
||||
|
||||
const res = await RestClient.request(config)
|
||||
|
||||
if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data
|
||||
|
||||
return res?.data
|
||||
},
|
||||
|
||||
/**
|
||||
* Replaces the user template contents.
|
||||
*
|
||||
|
92
src/fireedge/src/client/formSchema/Vm/resize.js
Normal file
92
src/fireedge/src/client/formSchema/Vm/resize.js
Normal file
@ -0,0 +1,92 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
/* eslint-disable jsdoc/require-jsdoc */
|
||||
import * as yup from 'yup'
|
||||
import { INPUT_TYPES } from 'client/constants'
|
||||
import { getValidationFromFields } from 'client/utils'
|
||||
|
||||
const ENFORCE = {
|
||||
name: 'enforce',
|
||||
label: 'Enforce capacity checks',
|
||||
type: INPUT_TYPES.CHECKBOX,
|
||||
tooltip: `
|
||||
If it is set to true, the host capacity will be checked.
|
||||
This will only affect oneadmin requests, regular users
|
||||
resize requests will always be enforced`,
|
||||
validation: yup
|
||||
.boolean()
|
||||
.transform(value => {
|
||||
if (typeof value === 'boolean') return value
|
||||
|
||||
return String(value).toUpperCase() === 'YES'
|
||||
})
|
||||
.default(false),
|
||||
grid: { md: 12 }
|
||||
}
|
||||
|
||||
const MEMORY = {
|
||||
name: 'MEMORY',
|
||||
label: 'Memory',
|
||||
type: INPUT_TYPES.TEXT,
|
||||
htmlType: 'number',
|
||||
tooltip: 'Amount of RAM required for the VM',
|
||||
validation: yup
|
||||
.number()
|
||||
.typeError('Memory value must be a number')
|
||||
.required('Memory field is required')
|
||||
.positive()
|
||||
.default(undefined)
|
||||
}
|
||||
|
||||
const PHYSICAL_CPU = {
|
||||
name: 'CPU',
|
||||
label: 'Physical CPU',
|
||||
type: INPUT_TYPES.TEXT,
|
||||
htmlType: 'number',
|
||||
tooltip: `
|
||||
Percentage of CPU divided by 100 required for the
|
||||
Virtual Machine. Half a processor is written 0.5.`,
|
||||
validation: yup
|
||||
.number()
|
||||
.typeError('Physical CPU value must be a number')
|
||||
.required('Physical CPU field is required')
|
||||
.positive()
|
||||
.default(undefined)
|
||||
.resolve()
|
||||
}
|
||||
|
||||
const VIRTUAL_CPU = {
|
||||
name: 'VCPU',
|
||||
label: 'Virtual CPU',
|
||||
type: INPUT_TYPES.TEXT,
|
||||
htmlType: 'number',
|
||||
tooltip: `
|
||||
Number of virtual cpus. This value is optional, the default
|
||||
hypervisor behavior is used, usually one virtual CPU.`,
|
||||
validation: yup
|
||||
.number()
|
||||
.typeError('Virtual CPU value must be a number')
|
||||
.default(undefined)
|
||||
}
|
||||
|
||||
export const FIELDS = [
|
||||
ENFORCE,
|
||||
MEMORY,
|
||||
PHYSICAL_CPU,
|
||||
VIRTUAL_CPU
|
||||
]
|
||||
|
||||
export const SCHEMA = yup.object(getValidationFromFields(FIELDS))
|
Loading…
x
Reference in New Issue
Block a user