mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-25 12:59:06 +01:00
subcluster in metricSelect, add infobox to systems
- Default: Show Clusters next to Metrics - New: If Cluster filter activem show subclusters instead (reactive) - add note to analysis view - systems view now with info boxes if metric is removed for subcluster
This commit is contained in:
parent
68a839bf1c
commit
adc1d94e3f
@ -269,7 +269,7 @@ func (r *queryResolver) NodeMetrics(ctx context.Context, cluster string, nodes [
|
|||||||
for _, scopedMetric := range scopedMetrics {
|
for _, scopedMetric := range scopedMetrics {
|
||||||
host.Metrics = append(host.Metrics, &model.JobMetricWithName{
|
host.Metrics = append(host.Metrics, &model.JobMetricWithName{
|
||||||
Name: metric,
|
Name: metric,
|
||||||
Scope: schema.MetricScopeNode, // NodeMetrics allow fixed scope?
|
Scope: schema.MetricScopeNode,
|
||||||
Metric: scopedMetric,
|
Metric: scopedMetric,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -216,6 +216,7 @@
|
|||||||
<Col>
|
<Col>
|
||||||
<Card body>
|
<Card body>
|
||||||
These histograms show the distribution of the averages of all jobs matching the filters. Each job/average is weighted by its node hours.
|
These histograms show the distribution of the averages of all jobs matching the filters. Each job/average is weighted by its node hours.
|
||||||
|
Note that some metrics could be disabled for specific subclusters as per metriConfig and thus could affect shown average values.
|
||||||
</Card>
|
</Card>
|
||||||
<br/>
|
<br/>
|
||||||
</Col>
|
</Col>
|
||||||
@ -247,6 +248,7 @@
|
|||||||
<Col>
|
<Col>
|
||||||
<Card body>
|
<Card body>
|
||||||
Each circle represents one job. The size of a circle is proportional to its node hours. Darker circles mean multiple jobs have the same averages for the respective metrics.
|
Each circle represents one job. The size of a circle is proportional to its node hours. Darker circles mean multiple jobs have the same averages for the respective metrics.
|
||||||
|
Note that some metrics could be disabled for specific subclusters as per metriConfig and thus could affect shown average values.
|
||||||
</Card>
|
</Card>
|
||||||
<br/>
|
<br/>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -15,11 +15,15 @@
|
|||||||
|
|
||||||
export let filterPresets = {}
|
export let filterPresets = {}
|
||||||
|
|
||||||
let filters, jobList, matchedJobs = null
|
let filters = []
|
||||||
|
let jobList, matchedJobs = null
|
||||||
let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false, isMetricsSelectionOpen = false
|
let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false, isMetricsSelectionOpen = false
|
||||||
let metrics = filterPresets.cluster
|
let metrics = filterPresets.cluster
|
||||||
? ccconfig[`plot_list_selectedMetrics:${filterPresets.cluster}`] || ccconfig.plot_list_selectedMetrics
|
? ccconfig[`plot_list_selectedMetrics:${filterPresets.cluster}`] || ccconfig.plot_list_selectedMetrics
|
||||||
: ccconfig.plot_list_selectedMetrics
|
: ccconfig.plot_list_selectedMetrics
|
||||||
|
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null
|
||||||
|
|
||||||
|
$: selectedCluster = filters[0]?.cluster ? filters[0].cluster.eq : null
|
||||||
|
|
||||||
// The filterPresets are handled by the Filters component,
|
// The filterPresets are handled by the Filters component,
|
||||||
// so we need to wait for it to be ready before we can start a query.
|
// so we need to wait for it to be ready before we can start a query.
|
||||||
@ -56,7 +60,10 @@
|
|||||||
<Filters
|
<Filters
|
||||||
filterPresets={filterPresets}
|
filterPresets={filterPresets}
|
||||||
bind:this={filters}
|
bind:this={filters}
|
||||||
on:update={({ detail }) => jobList.update(detail.filters)} />
|
on:update={({ detail }) => {
|
||||||
|
filters = detail.filters
|
||||||
|
jobList.update(detail.filters)}
|
||||||
|
} />
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col xs="3" style="margin-left: auto;">
|
<Col xs="3" style="margin-left: auto;">
|
||||||
@ -82,7 +89,7 @@
|
|||||||
bind:isOpen={isSortingOpen} />
|
bind:isOpen={isSortingOpen} />
|
||||||
|
|
||||||
<MetricSelection
|
<MetricSelection
|
||||||
cluster={filterPresets.cluster}
|
bind:cluster={selectedCluster}
|
||||||
configName="plot_list_selectedMetrics"
|
configName="plot_list_selectedMetrics"
|
||||||
bind:metrics={metrics}
|
bind:metrics={metrics}
|
||||||
bind:isOpen={isMetricsSelectionOpen} />
|
bind:isOpen={isMetricsSelectionOpen} />
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
|
|
||||||
<Modal isOpen={isOpen} toggle={() => (isOpen = !isOpen)}>
|
<Modal isOpen={isOpen} toggle={() => (isOpen = !isOpen)}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Configure columns
|
Configure columns (Metric availability shown)
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<ListGroup>
|
<ListGroup>
|
||||||
@ -113,9 +113,26 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{metric}
|
{metric}
|
||||||
<span style="float: right;">
|
<span style="float: right;">
|
||||||
{cluster == null ? clusters
|
{cluster == null ?
|
||||||
|
clusters // No single cluster specified: List Clusters with Metric
|
||||||
.filter(cluster => cluster.metricConfig.find(m => m.name == metric) != null)
|
.filter(cluster => cluster.metricConfig.find(m => m.name == metric) != null)
|
||||||
.map(cluster => cluster.name).join(', ') : ''}
|
.map(cluster => cluster.name).join(', ') :
|
||||||
|
clusters // Single cluster requested: List Subclusters with do not have metric remove flag
|
||||||
|
.filter(cluster => cluster.metricConfig.find(m => m.name == metric) != null)
|
||||||
|
.map(function(cluster) {
|
||||||
|
let scNames = cluster.subClusters.map(sc => sc.name)
|
||||||
|
scNames.forEach(function(scName){
|
||||||
|
let met = cluster.metricConfig.find(m => m.name == metric)
|
||||||
|
let msc = met.subClusters.find(msc => msc.name == scName)
|
||||||
|
if (msc != null) {
|
||||||
|
if (msc.remove == true) {
|
||||||
|
scNames = scNames.filter(scn => scn != msc.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return scNames
|
||||||
|
})
|
||||||
|
.join(', ')}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
const clusters = getContext('clusters')
|
const clusters = getContext('clusters')
|
||||||
const ccconfig = getContext('cc-config')
|
const ccconfig = getContext('cc-config')
|
||||||
|
const metricConfig = getContext('metrics')
|
||||||
|
|
||||||
let plotHeight = 300
|
let plotHeight = 300
|
||||||
let hostnameFilter = ''
|
let hostnameFilter = ''
|
||||||
@ -112,18 +113,35 @@
|
|||||||
itemsPerRow={ccconfig.plot_view_plotsPerRow}
|
itemsPerRow={ccconfig.plot_view_plotsPerRow}
|
||||||
items={$nodesQuery.data.nodeMetrics
|
items={$nodesQuery.data.nodeMetrics
|
||||||
.filter(h => h.host.includes(hostnameFilter) && h.metrics.some(m => m.name == selectedMetric && m.scope == 'node'))
|
.filter(h => h.host.includes(hostnameFilter) && h.metrics.some(m => m.name == selectedMetric && m.scope == 'node'))
|
||||||
.map(h => ({ host: h.host, subCluster: h.subCluster, data: h.metrics.find(m => m.name == selectedMetric && m.scope == 'node') }))
|
.map(function (h) {
|
||||||
|
let thisConfig = metricConfig(cluster, selectedMetric)
|
||||||
|
let thisSCIndex = thisConfig.subClusters.findIndex(sc => sc.name == h.subCluster)
|
||||||
|
// Metric remove == true
|
||||||
|
if (thisSCIndex >= 0) {
|
||||||
|
if (thisConfig.subClusters[thisSCIndex].remove == true) {
|
||||||
|
return { host: h.host, subCluster: h.subCluster, data: null, removed: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Else
|
||||||
|
return { host: h.host, subCluster: h.subCluster, data: h.metrics.find(m => m.name == selectedMetric && m.scope == 'node'), removed: false }
|
||||||
|
})
|
||||||
.sort((a, b) => a.host.localeCompare(b.host))}>
|
.sort((a, b) => a.host.localeCompare(b.host))}>
|
||||||
|
|
||||||
<h4 style="width: 100%; text-align: center;"><a href="/monitoring/node/{cluster}/{item.host}">{item.host} ({item.subCluster})</a></h4>
|
<h4 style="width: 100%; text-align: center;"><a href="/monitoring/node/{cluster}/{item.host}">{item.host} ({item.subCluster})</a></h4>
|
||||||
<MetricPlot
|
{#if item.removed == false && item.data != null}
|
||||||
width={width}
|
<MetricPlot
|
||||||
height={plotHeight}
|
width={width}
|
||||||
timestep={item.data.metric.timestep}
|
height={plotHeight}
|
||||||
series={item.data.metric.series}
|
timestep={item.data.metric.timestep}
|
||||||
metric={item.data.name}
|
series={item.data.metric.series}
|
||||||
cluster={clusters.find(c => c.name == cluster)}
|
metric={item.data.name}
|
||||||
subCluster={item.subCluster} />
|
cluster={clusters.find(c => c.name == cluster)}
|
||||||
|
subCluster={item.subCluster} />
|
||||||
|
{:else if item.removed == true && item.data == null}
|
||||||
|
<Card body color="info">Metric '{ selectedMetric }' disabled for subcluster '{ item.subCluster }'</Card>
|
||||||
|
{:else}
|
||||||
|
<Card body color="warning">Missing Data</Card>
|
||||||
|
{/if}
|
||||||
</PlotTable>
|
</PlotTable>
|
||||||
{/if}
|
{/if}
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -18,10 +18,12 @@
|
|||||||
export let user
|
export let user
|
||||||
export let filterPresets
|
export let filterPresets
|
||||||
|
|
||||||
let filters, jobList
|
let filters = []
|
||||||
|
let jobList
|
||||||
let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false
|
let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false
|
||||||
let metrics = ccconfig.plot_list_selectedMetrics, isMetricsSelectionOpen = false
|
let metrics = ccconfig.plot_list_selectedMetrics, isMetricsSelectionOpen = false
|
||||||
let w1, w2, histogramHeight = 250
|
let w1, w2, histogramHeight = 250
|
||||||
|
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null
|
||||||
|
|
||||||
const stats = operationStore(`
|
const stats = operationStore(`
|
||||||
query($filter: [JobFilter!]!) {
|
query($filter: [JobFilter!]!) {
|
||||||
@ -40,6 +42,12 @@
|
|||||||
pause: true
|
pause: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// filters[filters.findIndex(filter => filter.cluster != null)] ?
|
||||||
|
// filters[filters.findIndex(filter => filter.cluster != null)].cluster.eq :
|
||||||
|
// null
|
||||||
|
// Cluster filter has to be alwas @ first index, above will throw error
|
||||||
|
$: selectedCluster = filters[0]?.cluster ? filters[0].cluster.eq : null
|
||||||
|
|
||||||
query(stats)
|
query(stats)
|
||||||
|
|
||||||
onMount(() => filters.update())
|
onMount(() => filters.update())
|
||||||
@ -75,11 +83,12 @@
|
|||||||
startTimeQuickSelect={true}
|
startTimeQuickSelect={true}
|
||||||
bind:this={filters}
|
bind:this={filters}
|
||||||
on:update={({ detail }) => {
|
on:update={({ detail }) => {
|
||||||
let filters = [...detail.filters, { user: { eq: user.username } }]
|
let jobFilters = [...detail.filters, { user: { eq: user.username } }]
|
||||||
$stats.variables = { filter: filters }
|
$stats.variables = { filter: jobFilters }
|
||||||
$stats.context.pause = false
|
$stats.context.pause = false
|
||||||
$stats.reexecute()
|
$stats.reexecute()
|
||||||
jobList.update(filters)
|
filters = jobFilters
|
||||||
|
jobList.update(jobFilters)
|
||||||
}} />
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs="auto" style="margin-left: auto;">
|
<Col xs="auto" style="margin-left: auto;">
|
||||||
@ -171,6 +180,8 @@
|
|||||||
bind:sorting={sorting}
|
bind:sorting={sorting}
|
||||||
bind:isOpen={isSortingOpen} />
|
bind:isOpen={isSortingOpen} />
|
||||||
|
|
||||||
<MetricSelection configName="plot_list_selectedMetrics"
|
<MetricSelection
|
||||||
|
bind:cluster={selectedCluster}
|
||||||
|
configName="plot_list_selectedMetrics"
|
||||||
bind:metrics={metrics}
|
bind:metrics={metrics}
|
||||||
bind:isOpen={isMetricsSelectionOpen} />
|
bind:isOpen={isMetricsSelectionOpen} />
|
Loading…
Reference in New Issue
Block a user