mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-10-30 23:45:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			239 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Svelte
		
	
	
	
	
	
| <script>
 | |
|     import { init, checkMetricDisabled } from "./utils.js";
 | |
|     import {
 | |
|         Row,
 | |
|         Col,
 | |
|         InputGroup,
 | |
|         InputGroupText,
 | |
|         Icon,
 | |
|         Spinner,
 | |
|         Card,
 | |
|     } from "sveltestrap";
 | |
|     import { queryStore, gql, getContextClient } from "@urql/svelte";
 | |
|     import TimeSelection from "./filters/TimeSelection.svelte";
 | |
|     import Refresher from './joblist/Refresher.svelte';
 | |
|     import PlotTable from "./PlotTable.svelte";
 | |
|     import MetricPlot from "./plots/MetricPlot.svelte";
 | |
|     import { getContext } from "svelte";
 | |
| 
 | |
|     export let cluster;
 | |
|     export let hostname;
 | |
|     export let from = null;
 | |
|     export let to = null;
 | |
| 
 | |
|     const { query: initq } = init();
 | |
| 
 | |
|     if (from == null || to == null) {
 | |
|         to = new Date(Date.now());
 | |
|         from = new Date(to.getTime());
 | |
|         from.setMinutes(from.getMinutes() - 30);
 | |
|     }
 | |
| 
 | |
|     const ccconfig = getContext("cc-config");
 | |
|     const clusters = getContext("clusters");
 | |
|     const client = getContextClient();
 | |
|     const nodeMetricsQuery = gql`
 | |
|         query ($cluster: String!, $nodes: [String!], $from: Time!, $to: Time!) {
 | |
|             nodeMetrics(
 | |
|                 cluster: $cluster
 | |
|                 nodes: $nodes
 | |
|                 from: $from
 | |
|                 to: $to
 | |
|             ) {
 | |
|                 host
 | |
|                 subCluster
 | |
|                 metrics {
 | |
|                     name
 | |
|                     scope
 | |
|                     metric {
 | |
|                         timestep
 | |
|                         unit {
 | |
|                             base
 | |
|                             prefix
 | |
|                         }
 | |
|                         series {
 | |
|                             statistics {
 | |
|                                 min
 | |
|                                 avg
 | |
|                                 max
 | |
|                             }
 | |
|                             data
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     `;
 | |
| 
 | |
|     $: nodeMetricsData = queryStore({
 | |
|         client: client,
 | |
|         query: nodeMetricsQuery,
 | |
|         variables: {
 | |
|             cluster: cluster,
 | |
|             nodes: [hostname],
 | |
|             from: from.toISOString(),
 | |
|             to: to.toISOString(),
 | |
|         },
 | |
|     });
 | |
| 
 | |
|     let itemsPerPage = ccconfig.plot_list_jobsPerPage;
 | |
|     let page = 1;
 | |
|     let paging = { itemsPerPage, page };
 | |
|     let sorting = { field: "startTime", order: "DESC" };
 | |
|     $: filter = [
 | |
|         { cluster: { eq: cluster } },
 | |
|         { node: { contains: hostname } },
 | |
|         { state: ["running"] },
 | |
|         // {startTime: {
 | |
|         //     from: from.toISOString(),
 | |
|         //     to: to.toISOString()
 | |
|         // }}
 | |
|     ];
 | |
| 
 | |
|     const nodeJobsQuery = gql`
 | |
|         query (
 | |
|             $filter: [JobFilter!]!
 | |
|             $sorting: OrderByInput!
 | |
|             $paging: PageRequest!
 | |
|         ) {
 | |
|             jobs(filter: $filter, order: $sorting, page: $paging) {
 | |
|                 # items {
 | |
|                 #     id
 | |
|                 #     jobId
 | |
|                 # }
 | |
|                 count
 | |
|             }
 | |
|         }
 | |
|     `;
 | |
| 
 | |
|     $: nodeJobsData = queryStore({
 | |
|         client: client,
 | |
|         query: nodeJobsQuery,
 | |
|         variables: { paging, sorting, filter },
 | |
|     });
 | |
| 
 | |
|     let metricUnits = {};
 | |
|     $: if ($nodeMetricsData.data) {
 | |
|         let thisCluster = clusters.find((c) => c.name == cluster);
 | |
|         if (thisCluster) {
 | |
|             for (let metric of thisCluster.metricConfig) {
 | |
|                 if (metric.unit.prefix || metric.unit.base) {
 | |
|                     metricUnits[metric.name] =
 | |
|                         "(" +
 | |
|                         (metric.unit.prefix ? metric.unit.prefix : "") +
 | |
|                         (metric.unit.base ? metric.unit.base : "") +
 | |
|                         ")";
 | |
|                 } else {
 | |
|                     // If no unit defined: Omit Unit Display
 | |
|                     metricUnits[metric.name] = "";
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     const dateToUnixEpoch = (rfc3339) => Math.floor(Date.parse(rfc3339) / 1000);
 | |
| </script>
 | |
| 
 | |
| <Row>
 | |
|     {#if $initq.error}
 | |
|         <Card body color="danger">{$initq.error.message}</Card>
 | |
|     {:else if $initq.fetching}
 | |
|         <Spinner />
 | |
|     {:else}
 | |
|         <Col>
 | |
|             <InputGroup>
 | |
|                 <InputGroupText><Icon name="hdd" /></InputGroupText>
 | |
|                 <InputGroupText>{hostname} ({cluster})</InputGroupText>
 | |
|             </InputGroup>
 | |
|         </Col>
 | |
|         <Col>
 | |
|             {#if $nodeJobsData.fetching}
 | |
|                 <Spinner />
 | |
|             {:else if $nodeJobsData.data}
 | |
|                 Currently running jobs on this node: {$nodeJobsData.data.jobs
 | |
|                     .count}
 | |
|                 [
 | |
|                 <a
 | |
|                     href="/monitoring/jobs/?cluster={cluster}&state=running&node={hostname}"
 | |
|                     target="_blank">View in Job List</a
 | |
|                 > ]
 | |
|             {:else}
 | |
|                 No currently running jobs.
 | |
|             {/if}
 | |
|         </Col>
 | |
|         <Col>
 | |
|             <Refresher on:reload={() => {
 | |
|                 const diff = Date.now() - to
 | |
|                 from = new Date(from.getTime() + diff)
 | |
|                 to = new Date(to.getTime() + diff)
 | |
|             }} />
 | |
|         </Col>
 | |
|         <Col>
 | |
|             <TimeSelection bind:from bind:to />
 | |
|         </Col>
 | |
|     {/if}
 | |
| </Row>
 | |
| <br />
 | |
| <Row>
 | |
|     <Col>
 | |
|         {#if $nodeMetricsData.error}
 | |
|             <Card body color="danger">{$nodeMetricsData.error.message}</Card>
 | |
|         {:else if $nodeMetricsData.fetching || $initq.fetching}
 | |
|             <Spinner />
 | |
|         {:else}
 | |
|             <PlotTable
 | |
|                 let:item
 | |
|                 let:width
 | |
|                 renderFor="node"
 | |
|                 itemsPerRow={ccconfig.plot_view_plotsPerRow}
 | |
|                 items={$nodeMetricsData.data.nodeMetrics[0].metrics
 | |
|                     .map((m) => ({
 | |
|                         ...m,
 | |
|                         disabled: checkMetricDisabled(
 | |
|                             m.name,
 | |
|                             cluster,
 | |
|                             $nodeMetricsData.data.nodeMetrics[0].subCluster
 | |
|                         ),
 | |
|                     }))
 | |
|                     .sort((a, b) => a.name.localeCompare(b.name))}
 | |
|             >
 | |
|                 <h4 style="text-align: center; padding-top:15px;">
 | |
|                     {item.name}
 | |
|                     {metricUnits[item.name]}
 | |
|                 </h4>
 | |
|                 {#if item.disabled === false && item.metric}
 | |
|                     <MetricPlot
 | |
|                         {width}
 | |
|                         height={300}
 | |
|                         metric={item.name}
 | |
|                         timestep={item.metric.timestep}
 | |
|                         cluster={clusters.find((c) => c.name == cluster)}
 | |
|                         subCluster={$nodeMetricsData.data.nodeMetrics[0]
 | |
|                             .subCluster}
 | |
|                         series={item.metric.series}
 | |
|                         resources={[{hostname: hostname}]}
 | |
|                         forNode={true}
 | |
|                     />
 | |
|                 {:else if item.disabled === true && item.metric}
 | |
|                     <Card
 | |
|                         style="margin-left: 2rem;margin-right: 2rem;"
 | |
|                         body
 | |
|                         color="info"
 | |
|                         >Metric disabled for subcluster <code
 | |
|                             >{item.name}:{$nodeMetricsData.data.nodeMetrics[0]
 | |
|                                 .subCluster}</code
 | |
|                         ></Card
 | |
|                     >
 | |
|                 {:else}
 | |
|                     <Card
 | |
|                         style="margin-left: 2rem;margin-right: 2rem;"
 | |
|                         body
 | |
|                         color="warning"
 | |
|                         >No dataset returned for <code>{item.name}</code></Card
 | |
|                     >
 | |
|                 {/if}
 | |
|             </PlotTable>
 | |
|         {/if}
 | |
|     </Col>
 | |
| </Row>
 |