parent
af00adcfcc
commit
eb3760ee4a
@ -17,6 +17,7 @@
|
||||
- [Notifications] New notification page to provide important information about XOA (PR [#3904](https://github.com/vatesfr/xen-orchestra/pull/3904))
|
||||
- [VM] Ability to export a VM with zstd compression [#3773](https://github.com/vatesfr/xen-orchestra/issues/3773) (PR [#3891](https://github.com/vatesfr/xen-orchestra/pull/3891))
|
||||
- [Host/network] Display PIF speed [#3887](https://github.com/vatesfr/xen-orchestra/issues/3887) (PR [#3901](https://github.com/vatesfr/xen-orchestra/pull/3901))
|
||||
- [SR] Display iscsi paths and mark the SR with a yellow dot if one path is not available. [#3659](https://github.com/vatesfr/xen-orchestra/issues/3659) (PR [#3829](https://github.com/vatesfr/xen-orchestra/pull/3829))
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
@ -477,6 +477,7 @@ const TRANSFORMS = {
|
||||
host: link(obj, 'host'),
|
||||
SR: link(obj, 'SR'),
|
||||
device_config: obj.device_config,
|
||||
otherConfig: obj.other_config,
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -29,10 +29,14 @@ const messages = {
|
||||
noValue: 'None',
|
||||
compression: 'Compression',
|
||||
multipathing: 'Multipathing',
|
||||
multipathingDisabled: 'Multipathing disabled',
|
||||
enableMultipathing: 'Enable multipathing',
|
||||
disableMultipathing: 'Disable multipathing',
|
||||
enableAllHostsMultipathing: 'Enable all hosts multipathing',
|
||||
disableAllHostsMultipathing: 'Disable all hosts multipathing',
|
||||
paths: 'Paths',
|
||||
pbdDisconnected: 'PBD disconnected',
|
||||
hasInactivePath: 'Has an inactive path',
|
||||
|
||||
// ----- Modals -----
|
||||
alertOk: 'OK',
|
||||
@ -770,7 +774,10 @@ const messages = {
|
||||
hostStatus: 'Status',
|
||||
hostBuildNumber: 'Build number',
|
||||
hostIscsiName: 'iSCSI name',
|
||||
hostNoIscsiSr: 'Not connected to an iSCSI SR',
|
||||
hostMultipathingSrs: 'Click to see concerned SRs',
|
||||
hostMultipathingPaths:
|
||||
'{nActives, number} of {nPaths, number} path{nPaths, plural, one {} other {s}} ({ nSessions, number } iSCSI session{nSessions, plural, one {} other {s}})',
|
||||
hostMultipathingWarning:
|
||||
'The host{nHosts, plural, one {} other {s}} will lose the connection to the SRs. Do you want to continue?',
|
||||
hostXenServerVersion: 'Version',
|
||||
|
@ -593,3 +593,11 @@ export const generateRandomId = () =>
|
||||
Math.random()
|
||||
.toString(36)
|
||||
.slice(2)
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// it returns [nActivePaths, nPaths]
|
||||
export const getIscsiPaths = pbd => {
|
||||
const pathsInfo = pbd.otherConfig[`mpath-${pbd.device_config.SCSIid}`]
|
||||
return pathsInfo !== undefined ? JSON.parse(pathsInfo) : []
|
||||
}
|
||||
|
@ -1,16 +1,14 @@
|
||||
import _ from 'intl'
|
||||
import Component from 'base-component'
|
||||
import sum from 'lodash/sum'
|
||||
import Ellipsis, { EllipsisContainer } from 'ellipsis'
|
||||
import Icon from 'icon'
|
||||
import Link, { BlockLink } from 'link'
|
||||
import map from 'lodash/map'
|
||||
import React from 'react'
|
||||
import SingleLineRow from 'single-line-row'
|
||||
import size from 'lodash/size'
|
||||
import Tooltip from 'tooltip'
|
||||
import HomeTags from 'home-tags'
|
||||
import { Col } from 'grid'
|
||||
import { map, size, sum, some } from 'lodash'
|
||||
import { Text } from 'editable'
|
||||
import {
|
||||
createGetObject,
|
||||
@ -25,7 +23,7 @@ import {
|
||||
removeTag,
|
||||
setDefaultSr,
|
||||
} from 'xo'
|
||||
import { connectStore, formatSizeShort } from 'utils'
|
||||
import { connectStore, formatSizeShort, getIscsiPaths } from 'utils'
|
||||
|
||||
import styles from './index.css'
|
||||
|
||||
@ -43,10 +41,11 @@ import styles from './index.css'
|
||||
isSrShared
|
||||
),
|
||||
status: createSelector(
|
||||
(_, props) => Boolean(props.item.sm_config.multipathable),
|
||||
createGetObjectsOfType('PBD').filter((_, props) => pbd =>
|
||||
pbd.SR === props.item.id
|
||||
),
|
||||
pbds => {
|
||||
(multipathable, pbds) => {
|
||||
const nbAttached = sum(map(pbds, pbd => (pbd.attached ? 1 : 0)))
|
||||
const nbPbds = size(pbds)
|
||||
if (!nbPbds) {
|
||||
@ -55,8 +54,18 @@ import styles from './index.css'
|
||||
if (!nbAttached) {
|
||||
return 0
|
||||
}
|
||||
if (nbAttached < nbPbds) {
|
||||
return 1
|
||||
}
|
||||
|
||||
return nbAttached < nbPbds ? 1 : 2
|
||||
const hasInactivePath =
|
||||
multipathable &&
|
||||
some(pbds, pbd => {
|
||||
const [nActives, nPaths] = getIscsiPaths(pbd)
|
||||
return nActives !== nPaths
|
||||
})
|
||||
|
||||
return hasInactivePath ? 3 : 2
|
||||
}
|
||||
),
|
||||
})
|
||||
@ -99,6 +108,12 @@ export default class SrItem extends Component {
|
||||
<Icon icon='all-connected' />
|
||||
</Tooltip>
|
||||
)
|
||||
case 3:
|
||||
return (
|
||||
<Tooltip content={_('hasInactivePath')}>
|
||||
<Icon icon='some-connected' />
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,21 @@
|
||||
import _ from 'intl'
|
||||
import Component from 'base-component'
|
||||
import Copiable from 'copiable'
|
||||
import decorate from 'apply-decorators'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import SelectFiles from 'select-files'
|
||||
import StateButton from 'state-button'
|
||||
import TabButton from 'tab-button'
|
||||
import Upgrade from 'xoa-upgrade'
|
||||
import { compareVersions, connectStore, getIscsiPaths } from 'utils'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { createGetObjectsOfType, createSelector } from 'selectors'
|
||||
import { forEach, map, noop, isEmpty } from 'lodash'
|
||||
import { FormattedRelative, FormattedTime } from 'react-intl'
|
||||
import { Sr } from 'render-xo-item'
|
||||
import { Text } from 'editable'
|
||||
import { Toggle } from 'form'
|
||||
import { compareVersions, connectStore } from 'utils'
|
||||
import { FormattedRelative, FormattedTime } from 'react-intl'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { forEach, map, noop } from 'lodash'
|
||||
import { createGetObjectsOfType, createSelector } from 'selectors'
|
||||
import {
|
||||
detachHost,
|
||||
disableHost,
|
||||
@ -38,6 +41,42 @@ const formatPack = ({ name, author, description, version }, key) => (
|
||||
|
||||
const getPackId = ({ author, name }) => `${author}\0${name}`
|
||||
|
||||
const MultipathableSrs = decorate([
|
||||
connectStore({
|
||||
pbds: createGetObjectsOfType('PBD').filter((_, { hostId }) => pbd =>
|
||||
pbd.host === hostId && Boolean(pbd.otherConfig.multipathed)
|
||||
),
|
||||
}),
|
||||
({ pbds }) =>
|
||||
isEmpty(pbds) ? (
|
||||
<div>{_('hostNoIscsiSr')}</div>
|
||||
) : (
|
||||
<Container>
|
||||
{map(pbds, pbd => {
|
||||
const [nActives, nPaths] = getIscsiPaths(pbd)
|
||||
return (
|
||||
<Row key={pbd.id}>
|
||||
<Col>
|
||||
<Sr id={pbd.SR} link newTab container={false} />{' '}
|
||||
{nActives !== undefined &&
|
||||
nPaths !== undefined &&
|
||||
_('hostMultipathingPaths', {
|
||||
nActives,
|
||||
nPaths,
|
||||
nSessions: pbd.otherConfig.iscsi_sessions,
|
||||
})}
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
})}
|
||||
</Container>
|
||||
),
|
||||
])
|
||||
|
||||
MultipathableSrs.propTypes = {
|
||||
hostId: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
@connectStore(() => {
|
||||
const getPgpus = createGetObjectsOfType('PGPU')
|
||||
.pick((_, { host }) => host.$PGPUs)
|
||||
@ -199,6 +238,7 @@ export default class extends Component {
|
||||
handler={setHostsMultipathing}
|
||||
state={host.multipathing}
|
||||
/>
|
||||
{host.multipathing && <MultipathableSrs hostId={host.id} />}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -1,14 +1,17 @@
|
||||
import _ from 'intl'
|
||||
import decorate from 'apply-decorators'
|
||||
import Link from 'link'
|
||||
import React from 'react'
|
||||
import SortedTable from 'sorted-table'
|
||||
import StateButton from 'state-button'
|
||||
import { Text } from 'editable'
|
||||
import { noop } from 'utils'
|
||||
import { confirm } from 'modal'
|
||||
import { isEmpty, some } from 'lodash'
|
||||
import { Container, Row, Col } from 'grid'
|
||||
import { editHost, connectPbd, disconnectPbd, deletePbd, deletePbds } from 'xo'
|
||||
import { get } from '@xen-orchestra/defined'
|
||||
import { getIscsiPaths, noop } from 'utils'
|
||||
import { isEmpty, some } from 'lodash'
|
||||
import { provideState, injectState } from 'reaclette'
|
||||
import { Text } from 'editable'
|
||||
|
||||
const forgetHost = pbd =>
|
||||
confirm({
|
||||
@ -81,21 +84,58 @@ const HOST_ACTIONS = [
|
||||
},
|
||||
]
|
||||
|
||||
export default ({ hosts, pbds }) => (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
{!isEmpty(hosts) ? (
|
||||
<SortedTable
|
||||
actions={HOST_ACTIONS}
|
||||
collection={pbds}
|
||||
userData={hosts}
|
||||
columns={HOST_COLUMNS}
|
||||
/>
|
||||
) : (
|
||||
<h4 className='text-xs-center'>{_('noHost')}</h4>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
)
|
||||
const HOST_WITH_PATHS_COLUMNS = [
|
||||
...HOST_COLUMNS,
|
||||
{
|
||||
name: _('paths'),
|
||||
itemRenderer: (pbd, hosts) => {
|
||||
if (!pbd.attached) {
|
||||
return _('pbdDisconnected')
|
||||
}
|
||||
|
||||
if (!get(() => hosts[pbd.host].multipathing)) {
|
||||
return _('multipathingDisabled')
|
||||
}
|
||||
|
||||
const [nActives, nPaths] = getIscsiPaths(pbd)
|
||||
return (
|
||||
nActives !== undefined &&
|
||||
nPaths !== undefined &&
|
||||
_('hostMultipathingPaths', {
|
||||
nActives,
|
||||
nPaths,
|
||||
nSessions: pbd.otherConfig.iscsi_sessions,
|
||||
})
|
||||
)
|
||||
},
|
||||
sortCriteria: (pbd, hosts) => get(() => hosts[pbd.host].multipathing),
|
||||
},
|
||||
]
|
||||
|
||||
export default decorate([
|
||||
provideState({
|
||||
computed: {
|
||||
columns: (_, { sr }) =>
|
||||
sr.sm_config.multipathable ? HOST_WITH_PATHS_COLUMNS : HOST_COLUMNS,
|
||||
},
|
||||
}),
|
||||
injectState,
|
||||
({ state, hosts, pbds }) => (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
{!isEmpty(hosts) ? (
|
||||
<SortedTable
|
||||
actions={HOST_ACTIONS}
|
||||
collection={pbds}
|
||||
columns={state.columns}
|
||||
userData={hosts}
|
||||
/>
|
||||
) : (
|
||||
<h4 className='text-xs-center'>{_('noHost')}</h4>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
),
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user