Skip to content

Commit

Permalink
feat(xo-web/SR): list resource in a xostor tab
Browse files Browse the repository at this point in the history
changelog

remove unrelated changes

add stateUrlParam
  • Loading branch information
mathieu committed Apr 12, 2024
1 parent 2f962dd commit 601135a
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

> Users must be able to say: “Nice enhancement, I'm eager to test it”
- [XOSTOR] List linstor resources in the XOSTOR tab of an SR's view (PR [#7542](https://github.com/vatesfr/xen-orchestra/pull/7542))

### Bug fixes

> Users must be able to say: “I had this issue, happy to know it's fixed”
Expand All @@ -28,5 +30,6 @@
<!--packages-start-->

- xo-server patch
- xo-web minor

<!--packages-end-->
15 changes: 15 additions & 0 deletions packages/xo-server/src/api/xostor.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -411,3 +411,18 @@ destroyInterface.params = {
destroyInterface.resolve = {
sr: ['sr', 'SR', 'administrate'],
}
export async function healthCheck({ sr }) {
const xapi = this.getXapi(sr)
const pool = this.getObject(sr.$pool)
const groupName = this.getObject(sr.$PBDs[0]).device_config['group-name']

return JSON.parse(
await pluginCall(xapi, this.getObject(pool.master), 'linstor-manager', 'healthCheck', { groupName })
)
}
healthCheck.params = {
sr: { type: 'string' },
}
healthCheck.resolve = {
sr: ['sr', 'SR', 'view'],
}
6 changes: 6 additions & 0 deletions packages/xo-web/src/common/intl/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const messages = {
description: 'Description',
deleteSourceVm: 'Delete source VM',
disable: 'Disable',
diskState: 'Disk state',
download: 'Download',
enable: 'Enable',
expiration: 'Expiration',
Expand All @@ -23,12 +24,16 @@ const messages = {
esxiImportStopSourceDescription:
'Source VM stopped before the last delta transfer (after final snapshot). Needed to fully transfer a running VM',
esxiImportStopOnErrorDescription: 'Stop on the first error when importing VMs',
inUse: 'In use',
nImportVmsInParallel: 'Number of VMs to import in parallel',
node: 'Node',
stopOnError: 'Stop on error',
uuid: 'UUID',
vdi: 'VDI',
vmSrUsage: 'Storage: {used} used of {total} ({free} free)',

new: 'New',
nodeStatus: 'Node status',
notDefined: 'Not defined',
status: 'Status',
statusConnecting: 'Connecting',
Expand Down Expand Up @@ -2593,6 +2598,7 @@ const messages = {
pifsNotAttached: 'Not all PIFs are attached',
pifsNotStatic: 'Not all PIFs are static',
replication: 'Replication',
resourceList: 'Resource list',
rpuNoLongerAvailableIfXostor:
'As long as a XOSTOR storage is present in the pool, Rolling Pool Update will not be available',
selectDisks: 'Select disk(s)…',
Expand Down
3 changes: 3 additions & 0 deletions packages/xo-web/src/common/xo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,9 @@ export const subscribeCloudXoConfig = createSubscription(() =>
fetch('./rest/v0/cloud/xo-config').then(resp => resp.json())
)

export const subscribeXostorHealthCheck = sr =>
createSubscription(() => _call('xostor.healthCheck', { sr: resolveId(sr) }))

// System ============================================================

export const apiMethods = _call('system.getMethodsInfo')
Expand Down
3 changes: 3 additions & 0 deletions packages/xo-web/src/xo-app/sr/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import TabHosts from './tab-host'
import TabLogs from './tab-logs'
import TabStats from './tab-stats'
import TabXosan from './tab-xosan'
import TabXostor from './tab-xostor'

// ===================================================================

Expand All @@ -33,6 +34,7 @@ import TabXosan from './tab-xosan'
logs: TabLogs,
stats: TabStats,
xosan: TabXosan,
xostor: TabXostor,
})
@connectStore(() => {
const getSr = createGetObject()
Expand Down Expand Up @@ -127,6 +129,7 @@ export default class Sr extends Component {
{sr.SR_type === 'xosan' && <NavLink to={`/srs/${sr.id}/xosan`}>XOSAN</NavLink>}
<NavLink to={`/srs/${sr.id}/hosts`}>{_('hostsTabName')}</NavLink>
<NavLink to={`/srs/${sr.id}/logs`}>{_('logsTabName')}</NavLink>
{sr.SR_type === 'linstor' && <NavLink to={`/srs/${sr.id}/xostor`}>{_('xostor')}</NavLink>}
<NavLink to={`/srs/${sr.id}/advanced`}>{_('advancedTabName')}</NavLink>
</NavTabs>
</Col>
Expand Down
101 changes: 101 additions & 0 deletions packages/xo-web/src/xo-app/sr/tab-xostor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import _ from 'intl'
import Component from 'base-component'
import Icon from 'icon'
import React from 'react'
import SortedTable from 'sorted-table'

import { addSubscriptions, connectStore } from 'utils'
import { Card, CardHeader, CardBlock } from 'card'
import { Container, Row, Col } from 'grid'
import { createSelector, createGetObjectsOfType } from 'selectors'
import { Host, Vdi } from 'render-xo-item'
import { subscribeXostorHealthCheck } from 'xo'

const RESOURCE_COLUMNS = [
{
name: 'Resource name',
itemRenderer: ({ resourceName }) => resourceName,
sortCriteria: ({ resourceName }) => resourceName,
},
{
name: _('node'),
itemRenderer: ({ host }) => <Host id={host.id} link />,
sortCriteria: ({ host }) => host.name_label,
},
{
name: _('nodeStatus'),
itemRenderer: ({ nodeStatus }) => nodeStatus,
sortCriteria: ({ nodeStatus }) => nodeStatus,
},
{
name: _('vdi'),
itemRenderer: ({ volume }) => <Vdi id={volume.uuid} />,
},
{
name: _('inUse'),
itemRenderer: resource => <Icon icon={String(resource['in-use'])} />,
sortCriteria: resource => resource['in-use'],
},
{
name: _('diskState'),
itemRenderer: ({ volume }) => volume['disk-state'],
sortCriteria: ({ volume }) => volume['disk-state'],
},
]

@connectStore({
hostByHostname: createGetObjectsOfType('host')
.filter((_, props) => host => host.$pool === props.sr.$pool)
.groupBy('hostname'),
})
@addSubscriptions(({ sr }) => ({
healthCheck: subscribeXostorHealthCheck(sr.id),
}))
export default class TabXostor extends Component {
getResourceInfos = createSelector(
() => this.props.healthCheck,
healthCheck => {
if (healthCheck === undefined) {
return []
}

return Object.entries(healthCheck.resources).flatMap(([resourceName, resourceByHostname]) => {
return Object.entries(resourceByHostname).map(([hostname, resource]) => {
const host = this.props.hostByHostname[hostname][0]
const nodeStatus = healthCheck.nodes[hostname]
const volume = resource.volumes[0] // Always only one volume
delete resource.volumes

return {
...resource,
host,
nodeStatus,
resourceName,
volume,
}
})
})
}
)

render() {
const resourceInfos = this.getResourceInfos()

return (
<Container>
<Row>
<Col>
<Card>
<CardHeader>
<Icon icon='disk' /> {_('resourceList')}
</CardHeader>
<CardBlock>
<SortedTable collection={resourceInfos} columns={RESOURCE_COLUMNS} stateUrlParam='r' />
</CardBlock>
</Card>
</Col>
</Row>
</Container>
)
}
}

0 comments on commit 601135a

Please sign in to comment.