parent
ecc33f46ab
commit
dfe4a934e9
@ -4,6 +4,8 @@ import { forEach } from 'lodash'
|
||||
|
||||
import LocalHandler from './local'
|
||||
|
||||
const DEFAULT_NFS_OPTIONS = 'vers=3'
|
||||
|
||||
export default class NfsHandler extends LocalHandler {
|
||||
get type () {
|
||||
return 'nfs'
|
||||
@ -52,12 +54,12 @@ export default class NfsHandler extends LocalHandler {
|
||||
|
||||
async _mount () {
|
||||
await fs.ensureDir(this._getRealPath())
|
||||
const { host, path, port } = this._remote
|
||||
const { host, path, port, options } = this._remote
|
||||
return execa('mount', [
|
||||
'-t',
|
||||
'nfs',
|
||||
'-o',
|
||||
'vers=3',
|
||||
DEFAULT_NFS_OPTIONS + (options !== undefined ? `,${options}` : ''),
|
||||
`${host}${port !== undefined ? ':' + port : ''}:${path}`,
|
||||
this._getRealPath(),
|
||||
])
|
||||
|
@ -17,6 +17,7 @@
|
||||
- [New VM] Display an error when the getting of the coreOS default template fails [#3227](https://github.com/vatesfr/xen-orchestra/issues/3227) (PR [#3343](https://github.com/vatesfr/xen-orchestra/pull/3343))
|
||||
- [Backup NG form] Set default retention to 1 [#3134](https://github.com/vatesfr/xen-orchestra/issues/3134) (PR [#3290](https://github.com/vatesfr/xen-orchestra/pull/3290))
|
||||
- [Backup NG] New logs are searchable by job name [#3272](https://github.com/vatesfr/xen-orchestra/issues/3272) (PR [#3351](https://github.com/vatesfr/xen-orchestra/pull/3351))
|
||||
- [Remotes] Add a field for NFS remotes to set mount options [#1793](https://github.com/vatesfr/xen-orchestra/issues/1793) (PR [#3353](https://github.com/vatesfr/xen-orchestra/pull/3353))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
@ -35,8 +35,8 @@ list.params = {
|
||||
id: { type: 'string' },
|
||||
}
|
||||
|
||||
export async function create ({ name, url }) {
|
||||
return this.createRemote({ name, url })
|
||||
export async function create ({ name, url, options }) {
|
||||
return this.createRemote({ name, url, options })
|
||||
}
|
||||
|
||||
create.permission = 'admin'
|
||||
@ -44,10 +44,11 @@ create.description = 'Creates a new fs remote point'
|
||||
create.params = {
|
||||
name: { type: 'string' },
|
||||
url: { type: 'string' },
|
||||
options: { type: 'string', optional: true },
|
||||
}
|
||||
|
||||
export async function set ({ id, name, url, enabled }) {
|
||||
await this.updateRemote(id, { name, url, enabled })
|
||||
export async function set ({ id, name, url, options, enabled }) {
|
||||
await this.updateRemote(id, { name, url, options, enabled })
|
||||
}
|
||||
|
||||
set.permission = 'admin'
|
||||
@ -56,6 +57,7 @@ set.params = {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string', optional: true },
|
||||
url: { type: 'string', optional: true },
|
||||
options: { type: ['string', 'null'], optional: true },
|
||||
enabled: { type: 'boolean', optional: true },
|
||||
}
|
||||
|
||||
|
@ -88,17 +88,18 @@ export default class {
|
||||
return remote.properties
|
||||
}
|
||||
|
||||
async createRemote ({ name, url }) {
|
||||
async createRemote ({ name, url, options }) {
|
||||
const remote = await this._remotes.add({
|
||||
name,
|
||||
url,
|
||||
options,
|
||||
enabled: false,
|
||||
error: '',
|
||||
})
|
||||
return /* await */ this.updateRemote(remote.get('id'), { enabled: true })
|
||||
}
|
||||
|
||||
updateRemote (id, { name, url, enabled }) {
|
||||
updateRemote (id, { name, url, options, enabled }) {
|
||||
const handlers = this._handlers
|
||||
const handler = handlers[id]
|
||||
if (handler !== undefined) {
|
||||
@ -106,7 +107,12 @@ export default class {
|
||||
ignoreErrors.call(handler.forget())
|
||||
}
|
||||
|
||||
return this._updateRemote(id, { name, url, enabled })
|
||||
return this._updateRemote(id, {
|
||||
name,
|
||||
url,
|
||||
options,
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
|
||||
@synchronized()
|
||||
|
@ -465,6 +465,7 @@ const messages = {
|
||||
remotePath: 'Path',
|
||||
remoteState: 'State',
|
||||
remoteDevice: 'Device',
|
||||
remoteOptions: 'Options',
|
||||
remoteShare: 'Share',
|
||||
remoteAction: 'Action',
|
||||
remoteAuth: 'Auth',
|
||||
@ -482,6 +483,7 @@ const messages = {
|
||||
remoteNfsPlaceHolderHost: 'host *',
|
||||
remoteNfsPlaceHolderPort: 'Port',
|
||||
remoteNfsPlaceHolderPath: 'path/to/backup',
|
||||
remoteNfsPlaceHolderOptions: 'Custom mount options',
|
||||
remoteSmbPlaceHolderRemotePath: 'subfolder [path\\\\to\\\\backup]',
|
||||
remoteSmbPlaceHolderUsername: 'Username',
|
||||
remoteSmbPlaceHolderPassword: 'Password',
|
||||
|
@ -1948,8 +1948,10 @@ export const getRemote = remote =>
|
||||
error(_('getRemote'), err.message || String(err))
|
||||
)
|
||||
|
||||
export const createRemote = (name, url) =>
|
||||
_call('remote.create', { name, url })::tap(subscribeRemotes.forceRefresh)
|
||||
export const createRemote = (name, url, options) =>
|
||||
_call('remote.create', { name, url, options })::tap(
|
||||
subscribeRemotes.forceRefresh
|
||||
)
|
||||
|
||||
export const deleteRemote = remote =>
|
||||
_call('remote.delete', { id: resolveId(remote) })::tap(
|
||||
@ -1980,8 +1982,8 @@ export const disableRemote = remote =>
|
||||
subscribeRemotes.forceRefresh
|
||||
)
|
||||
|
||||
export const editRemote = (remote, { name, url }) =>
|
||||
_call('remote.set', resolveIds({ remote, name, url }))::tap(
|
||||
export const editRemote = (remote, { name, url, options }) =>
|
||||
_call('remote.set', resolveIds({ remote, name, url, options }))::tap(
|
||||
subscribeRemotes.forceRefresh
|
||||
)
|
||||
|
||||
|
@ -30,12 +30,14 @@ const _changeUrlElement = (value, { remote, element }) =>
|
||||
url: format({ ...remote, [element]: value === null ? undefined : value }),
|
||||
})
|
||||
const _showError = remote => alert(_('remoteConnectionFailed'), remote.error)
|
||||
const _editRemote = (name, { remote }) => editRemote(remote, { name })
|
||||
const _editRemoteName = (name, { remote }) => editRemote(remote, { name })
|
||||
const _editRemoteOptions = (options, { remote }) =>
|
||||
editRemote(remote, { options: options !== '' ? options : null })
|
||||
const COLUMN_NAME = {
|
||||
itemRenderer: (remote, { formatMessage }) => (
|
||||
<Text
|
||||
data-remote={remote}
|
||||
onChange={_editRemote}
|
||||
onChange={_editRemoteName}
|
||||
placeholder={formatMessage(messages.remoteMyNamePlaceHolder)}
|
||||
value={remote.name}
|
||||
/>
|
||||
@ -137,6 +139,16 @@ const COLUMNS_NFS_REMOTE = [
|
||||
|
||||
name: _('remoteDevice'),
|
||||
},
|
||||
{
|
||||
name: _('remoteOptions'),
|
||||
itemRenderer: remote => (
|
||||
<Text
|
||||
data-remote={remote}
|
||||
onChange={_editRemoteOptions}
|
||||
value={remote.options || ''}
|
||||
/>
|
||||
),
|
||||
},
|
||||
COLUMN_STATE,
|
||||
]
|
||||
const COLUMNS_SMB_REMOTE = [
|
||||
|
@ -28,6 +28,7 @@ export default [
|
||||
host: undefined,
|
||||
inputTypeId: generateRandomId(),
|
||||
name: undefined,
|
||||
options: undefined,
|
||||
password: undefined,
|
||||
path: undefined,
|
||||
port: undefined,
|
||||
@ -45,6 +46,7 @@ export default [
|
||||
domain = remote.domain,
|
||||
host = remote.host,
|
||||
name,
|
||||
options = remote.options,
|
||||
password = remote.password,
|
||||
path = remote.path,
|
||||
port = remote.port,
|
||||
@ -62,6 +64,7 @@ export default [
|
||||
type,
|
||||
username,
|
||||
}),
|
||||
options,
|
||||
}).then(reset)
|
||||
},
|
||||
createRemote: ({ reset }) => async (state, { remotes }) => {
|
||||
@ -78,6 +81,7 @@ export default [
|
||||
domain,
|
||||
host,
|
||||
name,
|
||||
options,
|
||||
password,
|
||||
path,
|
||||
port,
|
||||
@ -103,7 +107,7 @@ export default [
|
||||
}
|
||||
|
||||
const url = format(urlParams)
|
||||
return createRemote(name, url)
|
||||
return createRemote(name, url, options)
|
||||
.then(reset)
|
||||
.catch(err => error('Create Remote', err.message || String(err)))
|
||||
},
|
||||
@ -119,6 +123,7 @@ export default [
|
||||
domain = remote.domain || '',
|
||||
host = remote.host || '',
|
||||
name = remote.name || '',
|
||||
options = remote.options || '',
|
||||
password = remote.password || '',
|
||||
parsedPath,
|
||||
path = parsedPath || '',
|
||||
@ -212,6 +217,19 @@ export default [
|
||||
value={path}
|
||||
/>
|
||||
</div>
|
||||
<div className='input-group form-group'>
|
||||
<span className='input-group-addon'>-o</span>
|
||||
<input
|
||||
className='form-control'
|
||||
name='options'
|
||||
onChange={effects.linkState}
|
||||
placeholder={formatMessage(
|
||||
messages.remoteNfsPlaceHolderOptions
|
||||
)}
|
||||
type='text'
|
||||
value={options}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
)}
|
||||
{type === 'smb' && (
|
||||
|
Loading…
Reference in New Issue
Block a user