@@ -9,7 +9,7 @@ import peekFooterFromStream from 'vhd-lib/peekFooterFromVhdStream.js'
|
||||
|
||||
import AggregateError from './_AggregateError.mjs'
|
||||
|
||||
const { warn } = createLogger('xo:xapi:sr')
|
||||
const { error, warn } = createLogger('xo:xapi:sr')
|
||||
|
||||
const OC_MAINTENANCE = 'xo:maintenanceState'
|
||||
|
||||
@@ -146,6 +146,22 @@ class Sr {
|
||||
}
|
||||
}
|
||||
|
||||
async reclaimSpace(srRef) {
|
||||
const result = await this.call('host.call_plugin', this.pool.master, 'trim', 'do_trim', {
|
||||
sr_uuid: await this.getField('SR', srRef, 'uuid'),
|
||||
})
|
||||
|
||||
// Error example:
|
||||
// <?xml version="1.0" ?><trim_response><key_value_pair><key>errcode</key><value>TrimException</value></key_value_pair><key_value_pair><key>errmsg</key><value>blkdiscard: /dev/VG_XenStorage-f5775872-b5e7-98e5-488a-7194efdaf8f6/f5775872-b5e7-98e5-488a-7194efdaf8f6_trim_lv: BLKDISCARD ioctl failed: Operation not supported</value></key_value_pair></trim_response>
|
||||
const errMatch = result?.match(/<key>errcode<\/key><value>(.*?)<\/value>.*<key>errmsg<\/key><value>(.*?)<\/value>/)
|
||||
if (errMatch) {
|
||||
error(result)
|
||||
const err = new Error(errMatch[2])
|
||||
err.code = errMatch[1]
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async importVdi(
|
||||
$defer,
|
||||
ref,
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
- [REST API] Hosts' audit and system logs can be downloaded [#3968](https://github.com/vatesfr/xen-orchestra/issues/3968) (PR [#7048](https://github.com/vatesfr/xen-orchestra/pull/7048))
|
||||
- [Host/Advanced] New button to download system logs [#3968](https://github.com/vatesfr/xen-orchestra/issues/3968) (PR [#7048](https://github.com/vatesfr/xen-orchestra/pull/7048))
|
||||
- [Home/Hosts, Pools] Display host brand and version (PR [#7027](https://github.com/vatesfr/xen-orchestra/pull/7027))
|
||||
- [SR] Ability to reclaim space [#1204](https://github.com/vatesfr/xen-orchestra/issues/1204) (PR [#7054](https://github.com/vatesfr/xen-orchestra/pull/7054))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
||||
@@ -952,3 +952,19 @@ disableMaintenanceMode.permission = 'admin'
|
||||
disableMaintenanceMode.resolve = {
|
||||
sr: ['id', 'SR', 'operate'],
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
export async function reclaimSpace({ sr }) {
|
||||
await this.getXapiObject(sr).$reclaimSpace()
|
||||
}
|
||||
|
||||
reclaimSpace.description = 'reclaim freed space on SR'
|
||||
|
||||
reclaimSpace.params = {
|
||||
id: { type: 'string' },
|
||||
}
|
||||
|
||||
reclaimSpace.resolve = {
|
||||
sr: ['id', 'SR', 'operate'],
|
||||
}
|
||||
|
||||
@@ -857,6 +857,9 @@ const messages = {
|
||||
srsForget: 'Forget SRs',
|
||||
srRemoveButton: 'Remove this SR',
|
||||
srNoVdis: 'No VDIs in this storage',
|
||||
srReclaimSpace: 'Reclaim freed space',
|
||||
srReclaimSpaceConfirm: 'Are you sure you want to reclaim freed space on this SR?',
|
||||
srReclaimSpaceNotSupported: 'Space reclaim not supported. Only supported on block based/LVM based SRs.',
|
||||
|
||||
// ----- SR disks tab -----
|
||||
multipleActiveVdis: '{firstVdi} and {nVdis} more',
|
||||
|
||||
@@ -2250,6 +2250,24 @@ export const toggleSrMaintenanceMode = sr => {
|
||||
})
|
||||
}
|
||||
|
||||
export const reclaimSrSpace = async sr => {
|
||||
await confirm({
|
||||
icon: 'sr-reclaim-space',
|
||||
title: _('srReclaimSpace'),
|
||||
body: _('srReclaimSpaceConfirm'),
|
||||
})
|
||||
|
||||
try {
|
||||
await _call('sr.reclaimSpace', { id: resolveId(sr) })
|
||||
success(_('srReclaimSpace'))
|
||||
} catch (err) {
|
||||
if (err?.data?.message?.includes('Operation not supported')) {
|
||||
throw new Error('Space reclaim not supported. Only supported on block based/LVM based SRs.')
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// PBDs --------------------------------------------------------------
|
||||
|
||||
export const connectPbd = pbd => _call('pbd.connect', { id: resolveId(pbd) })
|
||||
|
||||
@@ -630,6 +630,10 @@
|
||||
@extend .fa;
|
||||
@extend .fa-share;
|
||||
}
|
||||
&-reclaim-space {
|
||||
@extend .fa;
|
||||
@extend .fa-gavel;
|
||||
}
|
||||
}
|
||||
// Host
|
||||
&-host {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Container, Row, Col } from 'grid'
|
||||
import { CustomFields } from 'custom-fields'
|
||||
import { createGetObjectsOfType } from 'selectors'
|
||||
import { createSelector } from 'reselect'
|
||||
import { createSrUnhealthyVdiChainsLengthSubscription, deleteSr, toggleSrMaintenanceMode } from 'xo'
|
||||
import { createSrUnhealthyVdiChainsLengthSubscription, deleteSr, reclaimSrSpace, toggleSrMaintenanceMode } from 'xo'
|
||||
import { flowRight, isEmpty, keys, sum, values } from 'lodash'
|
||||
|
||||
// ===================================================================
|
||||
@@ -58,7 +58,13 @@ export default ({ sr }) => (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col className='text-xs-right'>
|
||||
<TabButton btnStyle='danger' handler={deleteSr} handlerParam={sr} icon='sr-remove' labelId='srRemoveButton' />
|
||||
<TabButton
|
||||
btnStyle='primary'
|
||||
handler={reclaimSrSpace}
|
||||
handlerParam={sr}
|
||||
icon='sr-reclaim-space'
|
||||
labelId='srReclaimSpace'
|
||||
/>
|
||||
{sr.inMaintenanceMode ? (
|
||||
<TabButton
|
||||
btnStyle='warning'
|
||||
@@ -76,6 +82,7 @@ export default ({ sr }) => (
|
||||
labelId='enableMaintenanceMode'
|
||||
/>
|
||||
)}
|
||||
<TabButton btnStyle='danger' handler={deleteSr} handlerParam={sr} icon='sr-remove' labelId='srRemoveButton' />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
|
||||
Reference in New Issue
Block a user