diff --git a/src/models/volume.js b/src/models/volume.js index c1fc82d3..eba125af 100755 --- a/src/models/volume.js +++ b/src/models/volume.js @@ -59,6 +59,8 @@ export default { bulkUnmapMarkSnapChainRemovedModalVisible: false, updateSnapshotDataIntegrityModalVisible: false, updateBulkSnapshotDataIntegrityModalVisible: false, + updateFreezeFilesystemForSnapshotModalVisible: false, + updateBulkFreezeFilesystemForSnapshotModalVisible: false, isDetachBulk: false, changeVolumeActivate: '', defaultPvOrPvcName: '', @@ -102,6 +104,8 @@ export default { updateSnapshotDataIntegrityModalKey: Math.random(), updateBulkSnapshotDataIntegrityModalKey: Math.random(), updateReplicaSoftAntiAffinityModalKey: Math.random(), + updateFreezeFilesystemForSnapshotModalKey: Math.random(), + updateBulkFreezeFilesystemForSnapshotModalKey: Math.random(), socketStatus: 'closed', sorter: getSorter('volumeList.sorter'), customColumnList: window.__column__, // eslint-disable-line no-underscore-dangle @@ -322,6 +326,24 @@ export default { yield call(execAction, payload.url, payload.params) yield put({ type: 'query' }) }, + *updateFreezeFilesystemForSnapshot({ + payload, + }, { call, put }) { + yield put({ type: 'hideUpdateFreezeFilesystemForSnapshotModal' }) + yield call(execAction, payload.url, payload.params) + yield put({ type: 'query' }) + }, + *updateBulkFreezeFilesystemForSnapshot({ + payload, + }, { call, put }) { + yield put({ type: 'hideUpdateBulkFreezeFilesystemForSnapshotModal' }) + if (payload?.urls?.length > 0) { + for (let i = 0; i < payload.urls.length; i++) { + yield call(execAction, payload.urls[i], payload.params) + } + } + yield put({ type: 'query' }) + }, *accessModeUpdate({ payload, }, { call, put }) { @@ -802,6 +824,18 @@ export default { showUpdateBulkSnapshotDataIntegrityModal(state, action) { return { ...state, ...action.payload, updateBulkSnapshotDataIntegrityModalVisible: true, updateBulkSnapshotDataIntegrityModalKey: Math.random() } }, + showUpdateFreezeFilesystemForSnapshotModal(state, action) { + return { ...state, ...action.payload, updateFreezeFilesystemForSnapshotModalVisible: true, updateFreezeFilesystemForSnapshotModalKey: Math.random() } + }, + hideUpdateFreezeFilesystemForSnapshotModal(state, action) { + return { ...state, ...action.payload, updateFreezeFilesystemForSnapshotModalVisible: false, updateFreezeFilesystemForSnapshotModalKey: Math.random() } + }, + showUpdateBulkFreezeFilesystemForSnapshotModal(state, action) { + return { ...state, ...action.payload, updateBulkFreezeFilesystemForSnapshotModalVisible: true, updateBulkFreezeFilesystemForSnapshotModalKey: Math.random() } + }, + hideUpdateBulkFreezeFilesystemForSnapshotModal(state, action) { + return { ...state, ...action.payload, updateBulkFreezeFilesystemForSnapshotModalVisible: false, updateBulkFreezeFilesystemForSnapshotModalKey: Math.random() } + }, showUpdateAccessMode(state, action) { return { ...state, ...action.payload, updateAccessModeModalVisible: true, updateAccessModeModalKey: Math.random() } }, diff --git a/src/routes/volume/CreateVolume.js b/src/routes/volume/CreateVolume.js index c5cd6f6a..cbd60705 100644 --- a/src/routes/volume/CreateVolume.js +++ b/src/routes/volume/CreateVolume.js @@ -389,6 +389,15 @@ const modal = ({ )} } + + {getFieldDecorator('freezeFilesystemForSnapshot', { + initialValue: 'ignored', + })()} + {getFieldDecorator('revisionCounterDisabled', { valuePropName: 'checked', diff --git a/src/routes/volume/UpdateBulkFreezeFilesystemForSnapshotModal.js b/src/routes/volume/UpdateBulkFreezeFilesystemForSnapshotModal.js new file mode 100644 index 00000000..2f657025 --- /dev/null +++ b/src/routes/volume/UpdateBulkFreezeFilesystemForSnapshotModal.js @@ -0,0 +1,82 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Form, Select, Alert } from 'antd' +import { ModalBlur } from '../../components' +const FormItem = Form.Item +const { Option } = Select + +const formItemLayout = { + labelCol: { + span: 24, + }, + wrapperCol: { + span: 24, + }, +} + +const modal = ({ + items, + option, + visible, + onCancel, + onOk, + form: { + getFieldDecorator, + validateFields, + getFieldsValue, + }, +}) => { + function handleOk() { + validateFields((errors) => { + if (errors) { + return + } + const data = { + ...getFieldsValue(), + } + const urls = items.map((item) => item?.actions?.updateFreezeFilesystemForSnapshot) + + onOk(data, urls) + }) + } + + const modalOpts = { + title: 'Update Freeze Filesystem For Snapshot', + visible, + onCancel, + width: 600, + onOk: handleOk, + } + if (!items || items?.length === 0) { + return null + } + return ( + +
+ + {getFieldDecorator('freezeFilesystemForSnapshot', { + initialValue: 'ignored', + })()} + + +
+
+ ) +} + +modal.propTypes = { + form: PropTypes.object.isRequired, + visible: PropTypes.bool, + option: PropTypes.array, + onCancel: PropTypes.func, + items: PropTypes.array, + onOk: PropTypes.func, +} + +export default Form.create()(modal) diff --git a/src/routes/volume/UpdateBulkSnapshotDataIntegrityModal.js b/src/routes/volume/UpdateBulkSnapshotDataIntegrityModal.js index eb226ed7..70cb900c 100644 --- a/src/routes/volume/UpdateBulkSnapshotDataIntegrityModal.js +++ b/src/routes/volume/UpdateBulkSnapshotDataIntegrityModal.js @@ -67,7 +67,7 @@ const modal = ({ )}
diff --git a/src/routes/volume/UpdateBulkUnmapMarkSnapChainRemovedModal.js b/src/routes/volume/UpdateBulkUnmapMarkSnapChainRemovedModal.js index 0fdba121..90a9977d 100644 --- a/src/routes/volume/UpdateBulkUnmapMarkSnapChainRemovedModal.js +++ b/src/routes/volume/UpdateBulkUnmapMarkSnapChainRemovedModal.js @@ -61,7 +61,7 @@ const modal = ({ )} diff --git a/src/routes/volume/UpdateFreezeFilesystemForSnapshotModal.js b/src/routes/volume/UpdateFreezeFilesystemForSnapshotModal.js new file mode 100644 index 00000000..196a68e8 --- /dev/null +++ b/src/routes/volume/UpdateFreezeFilesystemForSnapshotModal.js @@ -0,0 +1,82 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Form, Select, Alert } from 'antd' +import { ModalBlur } from '../../components' +const FormItem = Form.Item +const { Option } = Select + +const formItemLayout = { + labelCol: { + span: 24, + }, + wrapperCol: { + span: 24, + }, +} + +const modal = ({ + item, + option, + visible, + onCancel, + onOk, + form: { + getFieldDecorator, + validateFields, + getFieldsValue, + }, +}) => { + function handleOk() { + validateFields((errors) => { + if (errors) { + return + } + const data = { + ...getFieldsValue(), + } + let url = item?.actions?.updateFreezeFilesystemForSnapshot + + onOk(data, url) + }) + } + + const modalOpts = { + title: 'Update Freeze Filesystem For Snapshot', + visible, + onCancel, + width: 600, + onOk: handleOk, + } + if (!item) { + return null + } + return ( + +
+ + {getFieldDecorator('freezeFilesystemForSnapshot', { + initialValue: item?.freezeFilesystemForSnapshot, + })()} + + +
+
+ ) +} + +modal.propTypes = { + form: PropTypes.object.isRequired, + visible: PropTypes.bool, + option: PropTypes.array, + onCancel: PropTypes.func, + item: PropTypes.object, + onOk: PropTypes.func, +} + +export default Form.create()(modal) diff --git a/src/routes/volume/UpdateSnapshotDataIntegrityModal.js b/src/routes/volume/UpdateSnapshotDataIntegrityModal.js index 0b5c4734..8c03bd24 100644 --- a/src/routes/volume/UpdateSnapshotDataIntegrityModal.js +++ b/src/routes/volume/UpdateSnapshotDataIntegrityModal.js @@ -60,7 +60,7 @@ const modal = ({ )} diff --git a/src/routes/volume/UpdateUnmapMarkSnapChainRemovedModal.js b/src/routes/volume/UpdateUnmapMarkSnapChainRemovedModal.js index 7b4b7ff0..0041c8cd 100644 --- a/src/routes/volume/UpdateUnmapMarkSnapChainRemovedModal.js +++ b/src/routes/volume/UpdateUnmapMarkSnapChainRemovedModal.js @@ -61,7 +61,7 @@ const modal = ({ )} diff --git a/src/routes/volume/VolumeActions.js b/src/routes/volume/VolumeActions.js index 6a276aa5..66e91c66 100644 --- a/src/routes/volume/VolumeActions.js +++ b/src/routes/volume/VolumeActions.js @@ -33,6 +33,7 @@ function actions({ showUpdateReplicaZoneSoftAntiAffinityModal, showUpdateReplicaDiskSoftAntiAffinityModal, showOfflineReplicaRebuildingModal, + showUpdateFreezeFilesystemForSnapshotModal, commandKeyDown, }) { const deleteWranElement = (record) => { @@ -152,6 +153,9 @@ function actions({ case 'updateOfflineReplicaRebuilding': showOfflineReplicaRebuildingModal(record) break + case 'updateFreezeFilesystemForSnapshot': + showUpdateFreezeFilesystemForSnapshotModal(record) + break case 'trimFilesystem': confirm({ title: 'Are you sure you want to trim the filesystem?', @@ -225,6 +229,7 @@ function actions({ { key: 'updateSnapshotMaxSize', name: 'Update Snapshot Max Size', disabled: false }, { key: 'updateReplicaDiskSoftAntiAffinity', name: 'Update Replica Disk Soft Anti Affinity', disabled: false }, { key: 'updateOfflineReplicaRebuilding', name: 'Update Offline Replica Rebuilding', disabled: false || selected.dataEngine !== 'v2' }, + { key: 'updateFreezeFilesystemForSnapshot', name: 'Update Freeze Filesystem For Snapshot', disabled: false }, ] const availableActions = [{ key: 'backups', name: 'Backups', disabled: selected.standby || isRestoring(selected) }, { key: 'delete', name: 'Delete' }] @@ -281,6 +286,7 @@ actions.propTypes = { trimFilesystem: PropTypes.func, showUpdateSnapshotDataIntegrityModal: PropTypes.func, engineUpgradePerNodeLimit: PropTypes.object, + showUpdateFreezeFilesystemForSnapshotModal: PropTypes.func, } export default actions diff --git a/src/routes/volume/VolumeBulkActions.js b/src/routes/volume/VolumeBulkActions.js index 0a6a2d3e..02491311 100644 --- a/src/routes/volume/VolumeBulkActions.js +++ b/src/routes/volume/VolumeBulkActions.js @@ -32,6 +32,7 @@ function bulkActions({ showUpdateReplicaZoneSoftAntiAffinityModal, showUpdateReplicaDiskSoftAntiAffinityModal, showOfflineReplicaRebuildingModal, + showUpdateBulkFreezeFilesystemForSnapshotModal, }) { const deleteWranElement = (rows) => { let workloadResources = [] @@ -136,6 +137,9 @@ function bulkActions({ case 'updateOfflineReplicaRebuilding': showOfflineReplicaRebuildingModal(selectedRows) break + case 'updateFreezeFilesystemForSnapshot': + showUpdateBulkFreezeFilesystemForSnapshotModal(selectedRows) + break case 'trimFilesystem': confirm({ title: `Are you sure you want to trim (${selectedRows.map(item => item.name).join(', ')}) Filesystem ?`, @@ -203,6 +207,7 @@ function bulkActions({ { key: 'updateReplicaDiskSoftAntiAffinity', name: 'Update Replica Disk Soft Anti Affinity', disabled() { return selectedRows.length === 0 } }, { key: 'updateOfflineReplicaRebuilding', name: 'Update Offline Replica Rebuilding', disabled() { return selectedRows.length === 0 || selectedRows.some((item) => item.dataEngine !== 'v2') } }, { key: 'trimFilesystem', name: 'Trim Filesystem', disabled() { return selectedRows.length === 0 || notAttached() } }, + { key: 'updateFreezeFilesystemForSnapshot', name: 'Update Freeze Filesystem For Snapshot', disabled() { return selectedRows.length === 0 } }, ] const menu = ( @@ -258,6 +263,7 @@ bulkActions.propTypes = { commandKeyDown: PropTypes.bool, showBulkUnmapMarkSnapChainRemovedModal: PropTypes.func, trimBulkFilesystem: PropTypes.func, + showUpdateBulkFreezeFilesystemForSnapshotModal: PropTypes.func, } export default bulkActions diff --git a/src/routes/volume/VolumeList.js b/src/routes/volume/VolumeList.js index 8e6a304b..606f3f6d 100755 --- a/src/routes/volume/VolumeList.js +++ b/src/routes/volume/VolumeList.js @@ -58,6 +58,7 @@ function list({ showUpdateReplicaZoneSoftAntiAffinityModal, showUpdateReplicaDiskSoftAntiAffinityModal, showOfflineReplicaRebuildingModal, + showUpdateFreezeFilesystemForSnapshotModal, onRowClick = f => f, }) { const volumeActionsProps = { @@ -96,6 +97,7 @@ function list({ showUpdateReplicaZoneSoftAntiAffinityModal, showUpdateReplicaDiskSoftAntiAffinityModal, showOfflineReplicaRebuildingModal, + showUpdateFreezeFilesystemForSnapshotModal, onRowClick, } /** @@ -587,6 +589,7 @@ list.propTypes = { showUpdateSnapshotDataIntegrityModal: PropTypes.func, replicaSoftAntiAffinitySettingValue: PropTypes.bool, engineUpgradePerNodeLimit: PropTypes.object, + showUpdateFreezeFilesystemForSnapshotModal: PropTypes.func, } export default list diff --git a/src/routes/volume/detail/VolumeInfo.js b/src/routes/volume/detail/VolumeInfo.js index 389e9c46..36bb465a 100644 --- a/src/routes/volume/detail/VolumeInfo.js +++ b/src/routes/volume/detail/VolumeInfo.js @@ -368,6 +368,10 @@ function VolumeInfo({ selectedVolume, snapshotModalState, engineImages, hosts, c Replica Disk Soft Anti Affinity: {selectedVolume?.replicaDiskSoftAntiAffinity} +
+ Freeze Filesystem For Snapshot: + {addGlobalSettingDescription(selectedVolume?.freezeFilesystemForSnapshot)} +
{ selectedVolume.kubernetesStatus ?
{ selectedVolume.kubernetesStatus.lastPVCRefAt ?
Last time bound with PVC: diff --git a/src/routes/volume/detail/index.js b/src/routes/volume/detail/index.js index 5b7cd298..af443e2b 100644 --- a/src/routes/volume/detail/index.js +++ b/src/routes/volume/detail/index.js @@ -18,6 +18,7 @@ import UpdateAccessMode from '../UpdateAccessMode' import UpdateUnmapMarkSnapChainRemovedModal from '../UpdateUnmapMarkSnapChainRemovedModal' import UpdateSnapshotMaxCountModal from '../UpdateSnapshotMaxCountModal.js' import UpdateSnapshotMaxSizeModal from '../UpdateSnapshotMaxSizeModal.js' +import UpdateFreezeFilesystemForSnapshotModal from '../UpdateFreezeFilesystemForSnapshotModal' import Snapshots from './Snapshots' import RecurringJob from './RecurringJob' import EventList from './EventList' @@ -43,6 +44,7 @@ import { getUpdateOfflineReplicaRebuildingModalProps, getUpdateSnapshotMaxCountModalProps, getUpdateSnapshotMaxSizeModalProps, + getUpdateFreezeFilesystemForSnapshotModalProps, } from '../helper' const confirm = Modal.confirm @@ -88,6 +90,8 @@ function VolumeDetail({ snapshotModal, dispatch, backup, engineimage, eventlog, detachHostModalKey, updateSnapshotMaxCountModalVisible, updateSnapshotMaxSizeModalVisible, + updateFreezeFilesystemForSnapshotModalKey, + updateFreezeFilesystemForSnapshotModalVisible, } = volume const { backupStatus, backupTargetAvailable, backupTargetMessage } = backup const { data: snapshotData, state: snapshotModalState } = snapshotModal @@ -462,6 +466,14 @@ function VolumeDetail({ snapshotModal, dispatch, backup, engineimage, eventlog, }) } }, + showUpdateFreezeFilesystemForSnapshotModal(record) { + dispatch({ + type: 'volume/showUpdateFreezeFilesystemForSnapshotModal', + payload: { + selected: record, + }, + }) + }, } const attachHostModalProps = getAttachHostModalProps([selectedVolume], hosts, attachHostModalVisible, dispatch) @@ -539,6 +551,7 @@ function VolumeDetail({ snapshotModal, dispatch, backup, engineimage, eventlog, const updateSnapshotMaxCountModalProps = getUpdateSnapshotMaxCountModalProps(selectedVolume, updateSnapshotMaxCountModalVisible, dispatch) const updateSnapshotMaxSizeModalProps = getUpdateSnapshotMaxSizeModalProps(selectedVolume, updateSnapshotMaxSizeModalVisible, dispatch) + const updateFreezeFilesystemForSnapshotModalProps = getUpdateFreezeFilesystemForSnapshotModalProps(selectedVolume, updateFreezeFilesystemForSnapshotModalVisible, dispatch) const createPVAndPVCSingleProps = { item: { defaultPVName, @@ -671,6 +684,7 @@ function VolumeDetail({ snapshotModal, dispatch, backup, engineimage, eventlog, {updateReplicaAutoBalanceModalVisible ? : ''} {updateReplicaSoftAntiAffinityVisible ? : ''} {updateOfflineReplicaRebuildingVisible ? : ''} + {updateFreezeFilesystemForSnapshotModalVisible ? : ''}
) diff --git a/src/routes/volume/helper/index.js b/src/routes/volume/helper/index.js index 5e56f003..82d0f71c 100644 --- a/src/routes/volume/helper/index.js +++ b/src/routes/volume/helper/index.js @@ -399,6 +399,70 @@ export function getUpdateBulkDataLocalityModalProps(volumes, visible, defaultDat } } +export function getUpdateFreezeFilesystemForSnapshotModalProps(volume, visible, dispatch) { + let option = [ + { key: 'Enabled', value: 'enabled' }, + { key: 'Disabled', value: 'disabled' }, + { key: 'Ignored (Follow the global setting)', value: 'ignored' }, + ] + + return { + item: volume, + option, + visible, + onOk(v, url) { + dispatch({ + type: 'volume/updateFreezeFilesystemForSnapshot', + payload: { + params: v, + url, + }, + }) + }, + onCancel() { + dispatch({ + type: 'volume/hideUpdateFreezeFilesystemForSnapshotModal', + }) + dispatch({ + type: 'app/changeBlur', + payload: false, + }) + }, + } +} + +export function getUpdateBulkFreezeFilesystemForSnapshotModalProps(volumes, visible, dispatch) { + const option = [ + { key: 'Enabled', value: 'enabled' }, + { key: 'Disabled', value: 'disabled' }, + { key: 'Ignored (Follow the global setting)', value: 'ignored' }, + ] + + return { + items: volumes, + option, + visible, + onOk(v, urls) { + dispatch({ + type: 'volume/updateBulkFreezeFilesystemForSnapshot', + payload: { + params: v, + urls, + }, + }) + }, + onCancel() { + dispatch({ + type: 'volume/hideUpdateBulkFreezeFilesystemForSnapshotModal', + }) + dispatch({ + type: 'app/changeBlur', + payload: false, + }) + }, + } +} + export function getUpdateAccessModeModalProps(volume, visible, dispatch) { return { item: volume, diff --git a/src/routes/volume/index.js b/src/routes/volume/index.js index 0debc890..1f3277e2 100644 --- a/src/routes/volume/index.js +++ b/src/routes/volume/index.js @@ -27,6 +27,8 @@ import UpdateUnmapMarkSnapChainRemovedModal from './UpdateUnmapMarkSnapChainRemo import UpdateBulkUnmapMarkSnapChainRemovedModal from './UpdateBulkUnmapMarkSnapChainRemovedModal' import UpdateSnapshotDataIntegrityModal from './UpdateSnapshotDataIntegrityModal' import UpdateBulkSnapshotDataIntegrityModal from './UpdateBulkSnapshotDataIntegrityModal' +import UpdateFreezeFilesystemForSnapshotModal from './UpdateFreezeFilesystemForSnapshotModal' +import UpdateBulkFreezeFilesystemForSnapshotModal from './UpdateBulkFreezeFilesystemForSnapshotModal' import UpdateAccessMode from './UpdateAccessMode' import UpdateBulkAccessMode from './UpdateBulkAccessMode' import UpdateReplicaAutoBalanceModal from './UpdateReplicaAutoBalanceModal' @@ -56,6 +58,8 @@ import { getDetachHostModalProps, getUpdateSnapshotMaxCountModalProps, getUpdateSnapshotMaxSizeModalProps, + getUpdateFreezeFilesystemForSnapshotModalProps, + getUpdateBulkFreezeFilesystemForSnapshotModalProps, } from './helper' import { healthyVolume, inProgressVolume, degradedVolume, detachedVolume, faultedVolume, filterVolume, isVolumeImageUpgradable, isVolumeSchedule } from '../../utils/filter' import C from '../../utils/constants' @@ -195,6 +199,10 @@ class Volume extends React.Component { isBulkDetach, updateSnapshotMaxCountModalVisible, updateSnapshotMaxSizeModalVisible, + updateFreezeFilesystemForSnapshotModalVisible, + updateFreezeFilesystemForSnapshotModalKey, + updateBulkFreezeFilesystemForSnapshotModalVisible, + updateBulkFreezeFilesystemForSnapshotModalKey, } = this.props.volume const hosts = this.props.host.data const backingImages = this.props.backingImage.data @@ -428,6 +436,14 @@ class Volume extends React.Component { }) } }, + showUpdateFreezeFilesystemForSnapshotModal(record) { + dispatch({ + type: 'volume/showUpdateFreezeFilesystemForSnapshotModal', + payload: { + selected: record, + }, + }) + }, rollback(record) { dispatch({ type: 'volume/rollback', @@ -1095,6 +1111,14 @@ class Volume extends React.Component { }) } }, + showUpdateBulkFreezeFilesystemForSnapshotModal(record) { + dispatch({ + type: 'volume/showUpdateBulkFreezeFilesystemForSnapshotModal', + payload: { + selectedRows: record, + }, + }) + }, } const createBackModalProps = { @@ -1177,6 +1201,8 @@ class Volume extends React.Component { const updateReplicaAutoBalanceModalProps = getUpdateReplicaAutoBalanceModalProps(selectedRows, updateReplicaAutoBalanceModalVisible, dispatch) const unmapMarkSnapChainRemovedModalProps = getUnmapMarkSnapChainRemovedModalProps(selected, unmapMarkSnapChainRemovedModalVisible, dispatch) const bulkUnmapMarkSnapChainRemovedModalProps = getBulkUnmapMarkSnapChainRemovedModalProps(selectedRows, bulkUnmapMarkSnapChainRemovedModalVisible, dispatch) + const updateFreezeFilesystemForSnapshotModalProps = getUpdateFreezeFilesystemForSnapshotModalProps(selected, updateFreezeFilesystemForSnapshotModalVisible, dispatch) + const updateBulkFreezeFilesystemForSnapshotModalProps = getUpdateBulkFreezeFilesystemForSnapshotModalProps(selectedRows, updateBulkFreezeFilesystemForSnapshotModalVisible, dispatch) const detachHostModalProps = getDetachHostModalProps(!isBulkDetach && selected ? [selected] : selectedRows, detachHostModalVisible, dispatch) return ( @@ -1223,6 +1249,8 @@ class Volume extends React.Component { {updateBulkSnapshotDataIntegrityModalVisible ? : ''} {updateReplicaSoftAntiAffinityVisible ? : ''} {updateOfflineReplicaRebuildingVisible ? : ''} + {updateFreezeFilesystemForSnapshotModalVisible ? : ''} + {updateBulkFreezeFilesystemForSnapshotModalVisible ? : ''} {me.state.createBackModalVisible ? : ''} )