Compare commits
15 Commits
xo-web-v5.
...
select-nfs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2951f617b | ||
|
|
0ea64bdca7 | ||
|
|
f06bee3737 | ||
|
|
2693598ac8 | ||
|
|
19011ad372 | ||
|
|
86eb7744a1 | ||
|
|
fe13ef6ff9 | ||
|
|
5607d34719 | ||
|
|
4501018dd6 | ||
|
|
9be9007fde | ||
|
|
2b4443f333 | ||
|
|
ab6548122f | ||
|
|
f81573d999 | ||
|
|
84ccebb858 | ||
|
|
530bc50e7c |
@@ -4,10 +4,15 @@
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [VM/Advanced] Ability to use UEFI instead of BIOS [#4264](https://github.com/vatesfr/xen-orchestra/issues/4264) (PR [#4268](https://github.com/vatesfr/xen-orchestra/pull/4268))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- [XOA] Don't require editing the _email_ field in case of re-registration (PR [#4259](https://github.com/vatesfr/xen-orchestra/pull/4259))
|
||||
|
||||
### Released packages
|
||||
|
||||
- xen-api v0.25.2
|
||||
- xo-server v5.43.0
|
||||
- xo-web v5.43.0
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@
|
||||
|
||||
### Enhancements
|
||||
|
||||
- [VM/Advanced] Ability to use UEFI instead of BIOS [#4264](https://github.com/vatesfr/xen-orchestra/issues/4264) (PR [#4268](https://github.com/vatesfr/xen-orchestra/pull/4268))
|
||||
- [Backup-ng/restore] Display size for full VM backup [#4009](https://github.com/vatesfr/xen-orchestra/issues/4009) (PR [#4245](https://github.com/vatesfr/xen-orchestra/pull/4245))
|
||||
- [Sr/new] Ability to select NFS version when creating NFS storage [#3951](https://github.com/vatesfr/xen-orchestra/issues/#3951) (PR [#4277](https://github.com/vatesfr/xen-orchestra/pull/4277))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- [XOA] Don't require editing the _email_ field in case of re-registration (PR [#4259](https://github.com/vatesfr/xen-orchestra/pull/4259))
|
||||
|
||||
### Released packages
|
||||
|
||||
- xen-api v0.25.2
|
||||
- xo-server v5.43.0
|
||||
- xo-web v5.43.0
|
||||
- xo-server v5.44.0
|
||||
- xo-web v5.44.0
|
||||
|
||||
@@ -49,6 +49,11 @@ maxTokenValidity = '0.5 year'
|
||||
# Delay for which backups listing on a remote is cached
|
||||
listingDebounce = '1 min'
|
||||
|
||||
# Duration for which we can wait for the backup size before returning
|
||||
#
|
||||
# It should be short to avoid blocking the display of the available backups.
|
||||
vmBackupSizeTimeout = '2 seconds'
|
||||
|
||||
# Helmet handles HTTP security via headers
|
||||
#
|
||||
# https://helmetjs.github.io/docs/
|
||||
|
||||
@@ -322,6 +322,9 @@ create.params = {
|
||||
},
|
||||
|
||||
hvmBootFirmware: { type: 'string', optional: true },
|
||||
|
||||
// other params are passed to `editVm`
|
||||
'*': { type: 'any' },
|
||||
}
|
||||
|
||||
create.resolve = {
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
ignoreErrors,
|
||||
pFinally,
|
||||
pFromEvent,
|
||||
timeout,
|
||||
} from 'promise-toolbox'
|
||||
import Vhd, {
|
||||
chainVhd,
|
||||
@@ -41,6 +42,7 @@ import { type CallJob, type Executor, type Job } from '../jobs'
|
||||
import { type Schedule } from '../scheduling'
|
||||
|
||||
import createSizeStream from '../../size-stream'
|
||||
import parseDuration from '../../_parseDuration'
|
||||
import {
|
||||
type DeltaVmExport,
|
||||
type DeltaVmImport,
|
||||
@@ -544,10 +546,11 @@ export default class BackupNg {
|
||||
return this._runningRestores
|
||||
}
|
||||
|
||||
constructor(app: any) {
|
||||
constructor(app: any, { backup }) {
|
||||
this._app = app
|
||||
this._logger = undefined
|
||||
this._runningRestores = new Set()
|
||||
this._backupOptions = backup
|
||||
|
||||
app.on('start', async () => {
|
||||
this._logger = await app.getLogger('restore')
|
||||
@@ -1797,6 +1800,16 @@ export default class BackupNg {
|
||||
const path = `${dir}/${file}`
|
||||
try {
|
||||
const metadata = JSON.parse(String(await handler.readFile(path)))
|
||||
if (metadata.mode === 'full') {
|
||||
metadata.size = await timeout
|
||||
.call(
|
||||
handler.getSize(resolveRelativeFromFile(path, metadata.xva)),
|
||||
parseDuration(this._backupOptions.vmBackupSizeTimeout)
|
||||
)
|
||||
.catch(err => {
|
||||
log.warn(`_listVmBackups, getSize`, { err })
|
||||
})
|
||||
}
|
||||
if (predicate === undefined || predicate(metadata)) {
|
||||
Object.defineProperty(metadata, '_filename', {
|
||||
value: path,
|
||||
|
||||
@@ -571,8 +571,9 @@ const messages = {
|
||||
newSrPasswordPlaceHolder: 'Password',
|
||||
newSrLvmDevicePlaceHolder: 'Device, e.g /dev/sda…',
|
||||
newSrLocalPathPlaceHolder: '/path/to/directory',
|
||||
newSrUseNfs4: 'Use NFSv4',
|
||||
newSrNfsDefaultVersion: 'Default NFS version',
|
||||
newSrNfsOptions: 'Comma delimited NFS options',
|
||||
newSrNfs: 'NFS version',
|
||||
reattachNewSrTooltip: 'Reattach SR',
|
||||
|
||||
// ------ New Network -----
|
||||
|
||||
@@ -504,6 +504,9 @@ const xoItemToRender = {
|
||||
{backup.mode}
|
||||
</span>{' '}
|
||||
<span className='tag tag-warning'>{backup.remote.name}</span>{' '}
|
||||
{backup.size !== undefined && (
|
||||
<span className='tag tag-info'>{formatSize(backup.size)}</span>
|
||||
)}{' '}
|
||||
<FormattedDate
|
||||
value={new Date(backup.timestamp)}
|
||||
month='long'
|
||||
|
||||
@@ -6,7 +6,7 @@ import Icon from 'icon'
|
||||
import React from 'react'
|
||||
import SortedTable from 'sorted-table'
|
||||
import Upgrade from 'xoa-upgrade'
|
||||
import { addSubscriptions, noop } from 'utils'
|
||||
import { addSubscriptions, formatSize, noop } from 'utils'
|
||||
import { confirm } from 'modal'
|
||||
import { error } from 'notification'
|
||||
import { FormattedDate } from 'react-intl'
|
||||
@@ -87,6 +87,12 @@ const BACKUPS_COLUMNS = [
|
||||
default: true,
|
||||
sortOrder: 'desc',
|
||||
},
|
||||
{
|
||||
name: _('labelSize'),
|
||||
itemRenderer: ({ size }) =>
|
||||
size !== undefined && size !== 0 && formatSize(size),
|
||||
sortCriteria: 'size',
|
||||
},
|
||||
{
|
||||
name: _('availableBackupsColumn'),
|
||||
itemRenderer: ({ count }) =>
|
||||
@@ -149,6 +155,7 @@ export default class Restore extends Component {
|
||||
})
|
||||
// TODO: perf
|
||||
let first, last
|
||||
let size = 0
|
||||
forEach(backupDataByVm, (data, vmId) => {
|
||||
first = { timestamp: Infinity }
|
||||
last = { timestamp: 0 }
|
||||
@@ -161,9 +168,13 @@ export default class Restore extends Component {
|
||||
first = backup
|
||||
}
|
||||
count[backup.mode] = (count[backup.mode] || 0) + 1
|
||||
|
||||
if (backup.size !== undefined) {
|
||||
size += backup.size
|
||||
}
|
||||
})
|
||||
|
||||
assign(data, { first, last, count, id: vmId })
|
||||
assign(data, { first, last, count, id: vmId, size })
|
||||
})
|
||||
|
||||
forEach(backupDataByVm, ({ backups }, vmId) => {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { confirm } from 'modal'
|
||||
import { adminOnly, connectStore, formatSize } from 'utils'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { injectIntl } from 'react-intl'
|
||||
import { Password, Select, Toggle } from 'form'
|
||||
import { Password, Select } from 'form'
|
||||
import { SelectHost } from 'select-objects'
|
||||
import {
|
||||
createFilter,
|
||||
@@ -46,6 +46,10 @@ import {
|
||||
|
||||
// ===================================================================
|
||||
|
||||
const NFS_VERSIONS = ['4', '4.1']
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class SelectScsiId extends Component {
|
||||
static propTypes = {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
@@ -237,6 +241,7 @@ export default class New extends Component {
|
||||
lockCreation: undefined,
|
||||
lun: undefined,
|
||||
luns: undefined,
|
||||
nfsVersion: '',
|
||||
hbaDevices: undefined,
|
||||
name: undefined,
|
||||
path: undefined,
|
||||
@@ -267,7 +272,16 @@ export default class New extends Component {
|
||||
server,
|
||||
username,
|
||||
} = this.refs
|
||||
const { host, iqn, lun, path, type, scsiId, nfs4, nfsOptions } = this.state
|
||||
const {
|
||||
host,
|
||||
iqn,
|
||||
lun,
|
||||
nfsOptions,
|
||||
nfsVersion,
|
||||
path,
|
||||
scsiId,
|
||||
type,
|
||||
} = this.state
|
||||
|
||||
const createMethodFactories = {
|
||||
nfs: () =>
|
||||
@@ -277,7 +291,7 @@ export default class New extends Component {
|
||||
description.value,
|
||||
server.value,
|
||||
path,
|
||||
nfs4 ? '4' : undefined,
|
||||
nfsVersion !== '' ? nfsVersion : undefined,
|
||||
nfsOptions
|
||||
),
|
||||
hba: async () => {
|
||||
@@ -522,6 +536,12 @@ export default class New extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
_handleNfsVersion = ({ target: { value } }) => {
|
||||
this.setState({
|
||||
nfsVersion: value,
|
||||
})
|
||||
}
|
||||
|
||||
_reattach = async uuid => {
|
||||
const { host, type } = this.state
|
||||
|
||||
@@ -566,6 +586,7 @@ export default class New extends Component {
|
||||
lockCreation,
|
||||
lun,
|
||||
luns,
|
||||
nfsVersion,
|
||||
path,
|
||||
paths,
|
||||
summary,
|
||||
@@ -657,10 +678,22 @@ export default class New extends Component {
|
||||
</div>
|
||||
</fieldset>,
|
||||
<fieldset>
|
||||
<label>{_('newSrUseNfs4')}</label>
|
||||
<div>
|
||||
<Toggle onChange={this.toggleState('nfs4')} />
|
||||
</div>
|
||||
<label htmlFor='selectNfsVersion'>{_('newSrNfs')}</label>
|
||||
<select
|
||||
className='form-control'
|
||||
id='selectNfsVersion'
|
||||
onChange={this._handleNfsVersion}
|
||||
value={nfsVersion}
|
||||
>
|
||||
<option value=''>
|
||||
{formatMessage(messages.newSrNfsDefaultVersion)}
|
||||
</option>
|
||||
{map(NFS_VERSIONS, option => (
|
||||
<option key={option} value={option}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</fieldset>,
|
||||
<fieldset>
|
||||
<label>{_('newSrNfsOptions')}</label>
|
||||
|
||||
Reference in New Issue
Block a user