mirror of
https://github.com/OpenNebula/one.git
synced 2024-12-25 23:21:29 +03:00
parent
6f6d0fb55f
commit
292b62d7ce
@ -0,0 +1,48 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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 PropTypes from 'prop-types'
|
||||
|
||||
import FormWithSchema from 'client/components/Forms/FormWithSchema'
|
||||
|
||||
import { SCHEMA, FIELDS } from 'client/components/Forms/Vm/MigrateForm/Steps/AdvancedOptions/schema'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
export const STEP_ID = 'advanced'
|
||||
|
||||
const Content = () => (
|
||||
<FormWithSchema
|
||||
cy='migrate-vm-advanced'
|
||||
id={STEP_ID}
|
||||
fields={FIELDS}
|
||||
/>
|
||||
)
|
||||
|
||||
const AdvancedOptions = () => ({
|
||||
id: STEP_ID,
|
||||
label: T.AdvancedOptions,
|
||||
resolver: SCHEMA,
|
||||
optionsValidate: { abortEarly: false },
|
||||
content: Content
|
||||
})
|
||||
|
||||
Content.propTypes = {
|
||||
data: PropTypes.any,
|
||||
setFormData: PropTypes.func,
|
||||
nics: PropTypes.array
|
||||
}
|
||||
|
||||
export default AdvancedOptions
|
@ -0,0 +1,48 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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 { boolean, string, object } from 'yup'
|
||||
|
||||
import { DatastoresTable } from 'client/components/Tables'
|
||||
import { getValidationFromFields } from 'client/utils'
|
||||
import { INPUT_TYPES } from 'client/constants'
|
||||
|
||||
const ENFORCE = {
|
||||
name: 'enforce',
|
||||
label: 'Enforce capacity checks',
|
||||
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.`,
|
||||
type: INPUT_TYPES.SWITCH,
|
||||
validation: boolean().default(() => false),
|
||||
grid: { md: 12 }
|
||||
}
|
||||
|
||||
const DATASTORE = {
|
||||
name: 'datastore',
|
||||
label: 'Select the new datastore',
|
||||
type: INPUT_TYPES.TABLE,
|
||||
Table: DatastoresTable,
|
||||
validation: string()
|
||||
.trim()
|
||||
.notRequired()
|
||||
.default(() => undefined),
|
||||
grid: { md: 12 }
|
||||
}
|
||||
|
||||
export const FIELDS = [ENFORCE, DATASTORE]
|
||||
|
||||
export const SCHEMA = object(getValidationFromFields(FIELDS))
|
@ -0,0 +1,64 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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 PropTypes from 'prop-types'
|
||||
|
||||
import { useListForm } from 'client/hooks'
|
||||
import { HostsTable } from 'client/components/Tables'
|
||||
|
||||
import { SCHEMA } from 'client/components/Forms/Vm/MigrateForm/Steps/HostsTable/schema'
|
||||
import { T } from 'client/constants'
|
||||
|
||||
export const STEP_ID = 'host'
|
||||
|
||||
const Content = ({ data, setFormData }) => {
|
||||
const { ID } = data?.[0] ?? {}
|
||||
|
||||
const {
|
||||
handleSelect,
|
||||
handleClear
|
||||
} = useListForm({ key: STEP_ID, setList: setFormData })
|
||||
|
||||
const handleSelectedRows = rows => {
|
||||
const { original = {} } = rows?.[0] ?? {}
|
||||
|
||||
original.ID !== undefined ? handleSelect(original) : handleClear()
|
||||
}
|
||||
|
||||
return (
|
||||
<HostsTable
|
||||
singleSelect
|
||||
onlyGlobalSearch
|
||||
onlyGlobalSelectedRows
|
||||
initialState={{ selectedRowIds: { [ID]: true } }}
|
||||
onSelectedRowsChange={handleSelectedRows}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const NetworkStep = () => ({
|
||||
id: STEP_ID,
|
||||
label: T.SelectHost,
|
||||
resolver: SCHEMA,
|
||||
content: Content
|
||||
})
|
||||
|
||||
Content.propTypes = {
|
||||
data: PropTypes.any,
|
||||
setFormData: PropTypes.func
|
||||
}
|
||||
|
||||
export default NetworkStep
|
@ -0,0 +1,24 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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 * as yup from 'yup'
|
||||
|
||||
export const SCHEMA = yup
|
||||
.array(yup.object())
|
||||
.min(1, 'Select the new Host')
|
||||
.max(1, 'Max. one host selected')
|
||||
.required('Host field is required')
|
||||
.ensure()
|
||||
.default(() => [])
|
@ -0,0 +1,31 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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 HostsTable, { STEP_ID as HOST_ID } from 'client/components/Forms/Vm/MigrateForm/Steps/HostsTable'
|
||||
import AdvancedOptions, { STEP_ID as ADVANCED_ID } from 'client/components/Forms/Vm/MigrateForm/Steps/AdvancedOptions'
|
||||
import { createSteps } from 'client/utils'
|
||||
|
||||
const Steps = createSteps(
|
||||
[HostsTable, AdvancedOptions],
|
||||
{
|
||||
transformBeforeSubmit: formData => {
|
||||
const { [HOST_ID]: [host] = [], [ADVANCED_ID]: advanced } = formData
|
||||
|
||||
return { host: host?.ID, ...advanced }
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
export default Steps
|
@ -0,0 +1,16 @@
|
||||
/* ------------------------------------------------------------------------- *
|
||||
* 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. *
|
||||
* ------------------------------------------------------------------------- */
|
||||
export { default } from 'client/components/Forms/Vm/MigrateForm/Steps'
|
@ -18,6 +18,7 @@ import ChangeUserForm from 'client/components/Forms/Vm/ChangeUserForm'
|
||||
import ChangeGroupForm from 'client/components/Forms/Vm/ChangeGroupForm'
|
||||
import CreateDiskSnapshotForm from 'client/components/Forms/Vm/CreateDiskSnapshotForm'
|
||||
import CreateSnapshotForm from 'client/components/Forms/Vm/CreateSnapshotForm'
|
||||
import MigrateForm from 'client/components/Forms/Vm/MigrateForm'
|
||||
import RecoverForm from 'client/components/Forms/Vm/RecoverForm'
|
||||
import ResizeCapacityForm from 'client/components/Forms/Vm/ResizeCapacityForm'
|
||||
import ResizeDiskForm from 'client/components/Forms/Vm/ResizeDiskForm'
|
||||
@ -31,6 +32,7 @@ export {
|
||||
ChangeGroupForm,
|
||||
CreateDiskSnapshotForm,
|
||||
CreateSnapshotForm,
|
||||
MigrateForm,
|
||||
RecoverForm,
|
||||
ResizeCapacityForm,
|
||||
ResizeDiskForm,
|
||||
|
@ -21,15 +21,20 @@ import { useFetch } from 'client/hooks'
|
||||
import { useDatastore, useDatastoreApi } from 'client/features/One'
|
||||
|
||||
import { SkeletonTable, EnhancedTable } from 'client/components/Tables'
|
||||
import { createColumns } from 'client/components/Tables/Enhanced/Utils'
|
||||
import DatastoreColumns from 'client/components/Tables/Datastores/columns'
|
||||
import DatastoreRow from 'client/components/Tables/Datastores/row'
|
||||
|
||||
const DatastoresTable = () => {
|
||||
const columns = useMemo(() => DatastoreColumns, [])
|
||||
const DatastoresTable = props => {
|
||||
const { view, getResourceView, filterPool } = useAuth()
|
||||
|
||||
const columns = useMemo(() => createColumns({
|
||||
filters: getResourceView('DATASTORE')?.filters,
|
||||
columns: DatastoreColumns
|
||||
}), [view])
|
||||
|
||||
const datastores = useDatastore()
|
||||
const { getDatastores } = useDatastoreApi()
|
||||
const { filterPool } = useAuth()
|
||||
|
||||
const { status, fetchRequest, loading, reloading, STATUS } = useFetch(getDatastores)
|
||||
const { INIT, PENDING } = STATUS
|
||||
@ -47,6 +52,7 @@ const DatastoresTable = () => {
|
||||
isLoading={loading || reloading}
|
||||
getRowId={row => String(row.ID)}
|
||||
RowComponent={DatastoreRow}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -59,7 +59,6 @@ export default makeStyles(
|
||||
gap: '1em',
|
||||
gridTemplateColumns: 'minmax(0, 1fr)',
|
||||
gridAutoRows: 'max-content',
|
||||
paddingBlock: '0.8em',
|
||||
'& > [role=row]': {
|
||||
padding: '0.8em',
|
||||
cursor: 'pointer',
|
||||
|
@ -21,15 +21,20 @@ import { useFetch } from 'client/hooks'
|
||||
import { useHost, useHostApi } from 'client/features/One'
|
||||
|
||||
import { SkeletonTable, EnhancedTable, EnhancedTableProps } from 'client/components/Tables'
|
||||
import { createColumns } from 'client/components/Tables/Enhanced/Utils'
|
||||
import HostColumns from 'client/components/Tables/Hosts/columns'
|
||||
import HostRow from 'client/components/Tables/Hosts/row'
|
||||
|
||||
const HostsTable = props => {
|
||||
const columns = useMemo(() => HostColumns, [])
|
||||
const { view, getResourceView, filterPool } = useAuth()
|
||||
|
||||
const columns = useMemo(() => createColumns({
|
||||
filters: getResourceView('HOST')?.filters,
|
||||
columns: HostColumns
|
||||
}), [view])
|
||||
|
||||
const hosts = useHost()
|
||||
const { getHosts } = useHostApi()
|
||||
const { filterPool } = useAuth()
|
||||
|
||||
const { status, fetchRequest, loading, reloading, STATUS } = useFetch(getHosts)
|
||||
const { INIT, PENDING } = STATUS
|
||||
|
@ -31,12 +31,13 @@ import {
|
||||
} from 'iconoir-react'
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useVmApi } from 'client/features/One'
|
||||
import { useDatastore, useVmApi } from 'client/features/One'
|
||||
import { Translate } from 'client/components/HOC'
|
||||
|
||||
import { RecoverForm, ChangeUserForm, ChangeGroupForm } from 'client/components/Forms/Vm'
|
||||
import { RecoverForm, ChangeUserForm, ChangeGroupForm, MigrateForm } from 'client/components/Forms/Vm'
|
||||
import { createActions } from 'client/components/Tables/Enhanced/Utils'
|
||||
import { PATH } from 'client/apps/sunstone/routesOne'
|
||||
import { getLastHistory } from 'client/models/VirtualMachine'
|
||||
import { T, VM_ACTIONS, MARKETPLACE_APP_ACTIONS, VM_ACTIONS_BY_STATE } from 'client/constants'
|
||||
|
||||
const isDisabled = action => rows => {
|
||||
@ -47,22 +48,31 @@ const isDisabled = action => rows => {
|
||||
return states.some(state => !VM_ACTIONS_BY_STATE[action]?.includes(state))
|
||||
}
|
||||
|
||||
const ListVmNames = ({ rows = [] }) => (
|
||||
<Typography>
|
||||
<Translate word={T.VMs} />
|
||||
{`: ${rows?.map?.(({ original }) => original?.NAME).join(', ')}`}
|
||||
</Typography>
|
||||
)
|
||||
const ListVmNames = ({ rows = [] }) => {
|
||||
const datastores = useDatastore()
|
||||
|
||||
const SubHeader = rows => {
|
||||
const isMultiple = rows?.length > 1
|
||||
const firstRow = rows?.[0]?.original
|
||||
return rows?.map?.(({ id, original }) => {
|
||||
const { ID, NAME } = original
|
||||
const { HID = '', HOSTNAME = '--', DS_ID = '' } = getLastHistory(original)
|
||||
const DS_NAME = datastores?.find(ds => ds?.ID === DS_ID)?.NAME ?? '--'
|
||||
|
||||
return isMultiple
|
||||
? <ListVmNames rows={rows} />
|
||||
: <>{`#${firstRow?.ID} ${firstRow?.NAME}`}</>
|
||||
return (
|
||||
<Typography key={`vm-${id}`} variant='inherit'>
|
||||
<Translate
|
||||
word={T.WhereIsRunning}
|
||||
values={[
|
||||
`#${ID} ${NAME}`,
|
||||
`#${HID} ${HOSTNAME}`,
|
||||
`#${DS_ID} ${DS_NAME}`
|
||||
]}
|
||||
/>
|
||||
</Typography>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
const SubHeader = rows => <ListVmNames rows={rows} />
|
||||
|
||||
const MessageToConfirmAction = rows => (
|
||||
<>
|
||||
<ListVmNames rows={rows} />
|
||||
@ -70,10 +80,6 @@ const MessageToConfirmAction = rows => (
|
||||
</>
|
||||
)
|
||||
|
||||
ListVmNames.displayName = 'ListVmNames'
|
||||
SubHeader.displayName = 'SubHeader'
|
||||
MessageToConfirmAction.displayName = 'MessageToConfirmAction'
|
||||
|
||||
const Actions = () => {
|
||||
const history = useHistory()
|
||||
const { view, getResourceView } = useAuth()
|
||||
@ -97,6 +103,9 @@ const Actions = () => {
|
||||
unresched,
|
||||
recover,
|
||||
changeOwnership,
|
||||
deploy,
|
||||
migrate,
|
||||
migrateLive,
|
||||
lock,
|
||||
unlock
|
||||
} = useVmApi()
|
||||
@ -270,20 +279,44 @@ const Actions = () => {
|
||||
accessor: VM_ACTIONS.DEPLOY,
|
||||
disabled: isDisabled(VM_ACTIONS.DEPLOY),
|
||||
name: T.Deploy,
|
||||
form: () => undefined,
|
||||
onSubmit: () => undefined
|
||||
form: MigrateForm,
|
||||
dialogProps: {
|
||||
title: T.Deploy,
|
||||
subheader: SubHeader
|
||||
},
|
||||
onSubmit: async (formData, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => deploy(id, formData)))
|
||||
await Promise.all(ids.map(id => getVm(id)))
|
||||
}
|
||||
}, {
|
||||
accessor: VM_ACTIONS.MIGRATE,
|
||||
disabled: isDisabled(VM_ACTIONS.MIGRATE),
|
||||
name: T.Migrate,
|
||||
form: () => undefined,
|
||||
onSubmit: () => undefined
|
||||
form: MigrateForm,
|
||||
dialogProps: {
|
||||
title: T.Migrate,
|
||||
subheader: SubHeader
|
||||
},
|
||||
onSubmit: async (formData, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => migrate(id, formData)))
|
||||
await Promise.all(ids.map(id => getVm(id)))
|
||||
}
|
||||
}, {
|
||||
accessor: VM_ACTIONS.MIGRATE_LIVE,
|
||||
disabled: isDisabled(VM_ACTIONS.MIGRATE_LIVE),
|
||||
name: T.MigrateLive,
|
||||
form: () => undefined,
|
||||
onSubmit: () => undefined
|
||||
form: MigrateForm,
|
||||
dialogProps: {
|
||||
title: T.Migrate,
|
||||
subheader: SubHeader
|
||||
},
|
||||
onSubmit: async (formData, rows) => {
|
||||
const ids = rows?.map?.(({ original }) => original?.ID)
|
||||
await Promise.all(ids.map(id => migrateLive(id, formData)))
|
||||
await Promise.all(ids.map(id => getVm(id)))
|
||||
}
|
||||
}, {
|
||||
accessor: VM_ACTIONS.HOLD,
|
||||
disabled: isDisabled(VM_ACTIONS.HOLD),
|
||||
|
@ -16,32 +16,35 @@
|
||||
import { memo } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Typography, Chip } from '@mui/material'
|
||||
import makeStyles from '@mui/styles/makeStyles'
|
||||
import { Typography, Chip, Box } from '@mui/material'
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
display: 'inline-flex',
|
||||
gap: '1em',
|
||||
width: '100%'
|
||||
},
|
||||
label: {
|
||||
flexGrow: 1
|
||||
}
|
||||
})
|
||||
|
||||
const DevTypography = memo(({ label, labelProps, color, chipProps }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<span className={classes.root}>
|
||||
<Typography {...labelProps} className={classes.label}>
|
||||
{label}
|
||||
</Typography>
|
||||
<Chip size='small' label='DEV' color={color} {...chipProps} />
|
||||
</span>
|
||||
)
|
||||
})
|
||||
const DevTypography = memo(({ label, labelProps, color, chipProps }) => (
|
||||
<Box
|
||||
component='span'
|
||||
display='inline-flex'
|
||||
gap='1em'
|
||||
width='100%'
|
||||
>
|
||||
<Typography
|
||||
flexGrow={1}
|
||||
variant='inherit'
|
||||
sx={{ textTransform: 'capitalize' }}
|
||||
{...labelProps}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
<Chip
|
||||
size='small'
|
||||
label='DEV'
|
||||
color={color}
|
||||
sx={{
|
||||
height: 'auto',
|
||||
cursor: 'inherit'
|
||||
}}
|
||||
{...chipProps}
|
||||
/>
|
||||
</Box>
|
||||
))
|
||||
|
||||
DevTypography.propTypes = {
|
||||
chipProps: PropTypes.object,
|
||||
|
@ -92,6 +92,7 @@ module.exports = {
|
||||
SaveAsTemplate: 'Save as Template',
|
||||
Search: 'Search',
|
||||
Select: 'Select',
|
||||
SelectHost: 'Select a host',
|
||||
SelectGroup: 'Select a group',
|
||||
SelectRequest: 'Select request',
|
||||
SelectVmTemplate: 'Select a VM Template',
|
||||
@ -309,6 +310,7 @@ module.exports = {
|
||||
/* VM schema - info */
|
||||
UserTemplate: 'User Template',
|
||||
Template: 'Template',
|
||||
WhereIsRunning: 'VM %1$s is currently running on Host %2$s and Datastore %3$s',
|
||||
/* VM schema - capacity */
|
||||
Capacity: 'Capacity',
|
||||
PhysicalCpu: 'Physical CPU',
|
||||
|
@ -19,7 +19,7 @@ import { Container, Box, Grid } from '@mui/material'
|
||||
|
||||
import { useAuth } from 'client/features/Auth'
|
||||
import { useFetchAll } from 'client/hooks'
|
||||
import { useUserApi, useImageApi, useVNetworkApi } from 'client/features/One'
|
||||
import { useUserApi, useImageApi, useVNetworkApi, useDatastoreApi } from 'client/features/One'
|
||||
|
||||
import * as Widgets from 'client/components/Widgets'
|
||||
import dashboardStyles from 'client/containers/Dashboard/Provision/styles'
|
||||
@ -31,6 +31,7 @@ function Dashboard () {
|
||||
const { getUsers } = useUserApi()
|
||||
const { getImages } = useImageApi()
|
||||
const { getVNetworks } = useVNetworkApi()
|
||||
const { getDatastores } = useDatastoreApi()
|
||||
|
||||
const { settings: { disableanimations } = {} } = useAuth()
|
||||
const classes = dashboardStyles({ disableanimations })
|
||||
@ -41,7 +42,8 @@ function Dashboard () {
|
||||
fetchRequestAll([
|
||||
getUsers(),
|
||||
getImages(),
|
||||
getVNetworks()
|
||||
getVNetworks(),
|
||||
getDatastores()
|
||||
])
|
||||
}, [])
|
||||
|
||||
|
@ -86,3 +86,6 @@ export const addScheduledAction = createAction(`${VM}/add/scheduled-action`, vmS
|
||||
export const updateScheduledAction = createAction(`${VM}/update/scheduled-action`, vmService.updateScheduledAction)
|
||||
export const deleteScheduledAction = createAction(`${VM}/delete/scheduled-action`, vmService.deleteScheduledAction)
|
||||
export const recover = createAction(`${VM}/recover`, vmService.recover)
|
||||
export const deploy = createAction(`${VM}/deploy`, vmService.deploy)
|
||||
export const migrate = createAction(`${VM}/migrate`, vmService.migrate)
|
||||
export const migrateLive = createAction(`${VM}/migrate-live`, vmService.migrate)
|
||||
|
@ -85,6 +85,9 @@ export const useVmApi = () => {
|
||||
unwrapDispatch(actions.updateScheduledAction({ id, ...data })),
|
||||
deleteScheduledAction: (id, data) =>
|
||||
unwrapDispatch(actions.deleteScheduledAction({ id, ...data })),
|
||||
recover: (id, operation) => unwrapDispatch(actions.recover({ id, operation }))
|
||||
recover: (id, operation) => unwrapDispatch(actions.recover({ id, operation })),
|
||||
deploy: (id, data) => unwrapDispatch(actions.deploy({ id, ...data })),
|
||||
migrate: (id, data) => unwrapDispatch(actions.migrate({ id, ...data, live: false })),
|
||||
migrateLive: (id, data) => unwrapDispatch(actions.migrate({ id, ...data, live: true }))
|
||||
}
|
||||
}
|
||||
|
@ -594,6 +594,59 @@ export const vmService = ({
|
||||
|
||||
if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data
|
||||
|
||||
return res?.data
|
||||
},
|
||||
|
||||
/**
|
||||
* Initiates the instance of the given VM id on the target host.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {string|number} params.id - Virtual machine id
|
||||
* @param {string|number} params.host - The target host id
|
||||
* @param {boolean} params.enforce
|
||||
* - If `true`, will enforce the Host capacity isn't over committed.
|
||||
* @param {string|number} params.datastore - The target datastore id.
|
||||
* It is optional, and can be set to -1 to let OpenNebula choose the datastore
|
||||
* @returns {number} Virtual machine id
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
deploy: async params => {
|
||||
const name = Actions.VM_DEPLOY
|
||||
const command = { name, ...Commands[name] }
|
||||
const config = requestConfig(params, command)
|
||||
|
||||
const res = await RestClient.request(config)
|
||||
|
||||
if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data
|
||||
|
||||
return res?.data
|
||||
},
|
||||
|
||||
/**
|
||||
* Migrates one virtual machine to the target host.
|
||||
*
|
||||
* @param {object} params - Request parameters
|
||||
* @param {string|number} params.id - Virtual machine id
|
||||
* @param {string|number} params.host - The target host id
|
||||
* @param {boolean} params.live
|
||||
* - If `true` we are indicating that we want live migration, otherwise `false`.
|
||||
* @param {boolean} params.enforce
|
||||
* - If `true`, will enforce the Host capacity isn't over committed.
|
||||
* @param {string|number} params.datastore - The target datastore id.
|
||||
* It is optional, and can be set to -1 to let OpenNebula choose the datastore
|
||||
* @param {0|1|2} params.type - Migration type: save (0), poweroff (1), poweroff-hard (2)
|
||||
* @returns {number} Virtual machine id
|
||||
* @throws Fails when response isn't code 200
|
||||
*/
|
||||
migrate: async params => {
|
||||
const name = Actions.VM_MIGRATE
|
||||
const command = { name, ...Commands[name] }
|
||||
const config = requestConfig(params, command)
|
||||
|
||||
const res = await RestClient.request(config)
|
||||
|
||||
if (!res?.id || res?.id !== httpCodes.ok.id) throw res?.data
|
||||
|
||||
return res?.data
|
||||
}
|
||||
})
|
||||
|
@ -120,11 +120,11 @@ module.exports = {
|
||||
params: {
|
||||
id: {
|
||||
from: resource,
|
||||
default: 0
|
||||
default: -1
|
||||
},
|
||||
host: {
|
||||
from: postBody,
|
||||
default: 0
|
||||
default: -1
|
||||
},
|
||||
enforce: {
|
||||
from: postBody,
|
||||
@ -156,13 +156,13 @@ module.exports = {
|
||||
params: {
|
||||
id: {
|
||||
from: resource,
|
||||
default: 0
|
||||
default: -1
|
||||
},
|
||||
host: {
|
||||
from: postBody,
|
||||
default: 0
|
||||
default: -1
|
||||
},
|
||||
liveMigration: {
|
||||
live: {
|
||||
from: postBody,
|
||||
default: false
|
||||
},
|
||||
@ -172,9 +172,9 @@ module.exports = {
|
||||
},
|
||||
datastore: {
|
||||
from: postBody,
|
||||
default: 0
|
||||
default: -1
|
||||
},
|
||||
migration: {
|
||||
type: {
|
||||
from: postBody,
|
||||
default: 0
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user