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