From 2cbe8e9517b4deb42484a22d10291966bdcbdf4e Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Fri, 11 Oct 2024 12:30:55 +0200 Subject: [PATCH] Split systems view into node-overview and node-list --- internal/routerConfig/routes.go | 35 +- web/frontend/src/Header.svelte | 2 +- web/frontend/src/Systems.root.svelte | 230 ++----------- web/frontend/src/header/NavbarLinks.svelte | 96 ++++-- web/frontend/src/systems.entrypoint.js | 1 + web/frontend/src/systems/NodeList.svelte | 322 ++++++++++++++++++ web/frontend/src/systems/NodeOverview.svelte | 232 +++++++++++++ .../src/systems/nodelist/NodeInfo.svelte | 152 +++++++++ .../src/systems/nodelist/NodeListRow.svelte | 207 +++++++++++ web/templates/monitoring/systems.tmpl | 1 + 10 files changed, 1032 insertions(+), 246 deletions(-) create mode 100644 web/frontend/src/systems/NodeList.svelte create mode 100644 web/frontend/src/systems/NodeOverview.svelte create mode 100644 web/frontend/src/systems/nodelist/NodeInfo.svelte create mode 100644 web/frontend/src/systems/nodelist/NodeListRow.svelte diff --git a/internal/routerConfig/routes.go b/internal/routerConfig/routes.go index 05b316d..e6cb376 100644 --- a/internal/routerConfig/routes.go +++ b/internal/routerConfig/routes.go @@ -42,10 +42,11 @@ var routes []Route = []Route{ {"/monitoring/projects/", "monitoring/list.tmpl", "Projects - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { i["listType"] = "PROJECT"; return i }}, {"/monitoring/tags/", "monitoring/taglist.tmpl", "Tags - ClusterCockpit", false, setupTaglistRoute}, {"/monitoring/user/{id}", "monitoring/user.tmpl", "User - ClusterCockpit", true, setupUserRoute}, - {"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster - ClusterCockpit", false, setupClusterRoute}, + {"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster Overview - ClusterCockpit", false, setupClusterOverviewRoute}, + {"/monitoring/systems/list/{cluster}", "monitoring/systems.tmpl", "Cluster List - ClusterCockpit", false, setupClusterListRoute}, {"/monitoring/node/{cluster}/{hostname}", "monitoring/node.tmpl", "Node - ClusterCockpit", false, setupNodeRoute}, {"/monitoring/analysis/{cluster}", "monitoring/analysis.tmpl", "Analysis - ClusterCockpit", true, setupAnalysisRoute}, - {"/monitoring/status/{cluster}", "monitoring/status.tmpl", "Status of - ClusterCockpit", false, setupClusterRoute}, + {"/monitoring/status/{cluster}", "monitoring/status.tmpl", "Status of - ClusterCockpit", false, setupClusterStatusRoute}, } func setupHomeRoute(i InfoType, r *http.Request) InfoType { @@ -96,7 +97,7 @@ func setupUserRoute(i InfoType, r *http.Request) InfoType { return i } -func setupClusterRoute(i InfoType, r *http.Request) InfoType { +func setupClusterStatusRoute(i InfoType, r *http.Request) InfoType { vars := mux.Vars(r) i["id"] = vars["cluster"] i["cluster"] = vars["cluster"] @@ -108,6 +109,34 @@ func setupClusterRoute(i InfoType, r *http.Request) InfoType { return i } +func setupClusterOverviewRoute(i InfoType, r *http.Request) InfoType { + vars := mux.Vars(r) + i["id"] = vars["cluster"] + i["cluster"] = vars["cluster"] + i["displayType"] = "OVERVIEW" + + from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to") + if from != "" || to != "" { + i["from"] = from + i["to"] = to + } + return i +} + +func setupClusterListRoute(i InfoType, r *http.Request) InfoType { + vars := mux.Vars(r) + i["id"] = vars["cluster"] + i["cluster"] = vars["cluster"] + i["displayType"] = "LIST" + + from, to := r.URL.Query().Get("from"), r.URL.Query().Get("to") + if from != "" || to != "" { + i["from"] = from + i["to"] = to + } + return i +} + func setupNodeRoute(i InfoType, r *http.Request) InfoType { vars := mux.Vars(r) i["cluster"] = vars["cluster"] diff --git a/web/frontend/src/Header.svelte b/web/frontend/src/Header.svelte index 9b12403..9a7ae79 100644 --- a/web/frontend/src/Header.svelte +++ b/web/frontend/src/Header.svelte @@ -97,7 +97,7 @@ href: "/monitoring/systems/", icon: "hdd-rack", perCluster: true, - listOptions: false, + listOptions: true, menu: "Info", }, { diff --git a/web/frontend/src/Systems.root.svelte b/web/frontend/src/Systems.root.svelte index 488cdad..baef2d0 100644 --- a/web/frontend/src/Systems.root.svelte +++ b/web/frontend/src/Systems.root.svelte @@ -1,232 +1,44 @@ - - {#if $initq.error} - {$initq.error.message} - {:else if $initq.fetching} - - {:else} - - - - - Find Node - - - - - - - - - - - - Metric - - - - - - { - const diff = Date.now() - to; - from = new Date(from.getTime() + diff); - to = new Date(to.getTime() + diff); - }} - /> - - {/if} - -
-{#if $nodesQuery.error} - - - {$nodesQuery.error.message} - - -{:else if $nodesQuery.fetching || $initq.fetching} - - - - - +{#if displayType === 'OVERVIEW'} + +{:else if displayType === 'LIST'} + {:else} - - 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", - ), - disabled: checkMetricDisabled( - selectedMetric, - cluster, - h.subCluster, - ), - })) - .sort((a, b) => a.host.localeCompare(b.host))} - > -

- {item.host} ({item.subCluster}) -

- {#if item.disabled === false && item.data} - c.name == cluster)} - subCluster={item.subCluster} - forNode={true} - /> - {:else if item.disabled === true && item.data} - Metric disabled for subcluster {selectedMetric}:{item.subCluster} - {:else} - No dataset returned for {selectedMetric} - {/if} -
+ + + + Unknown displayList type! + + + {/if} diff --git a/web/frontend/src/header/NavbarLinks.svelte b/web/frontend/src/header/NavbarLinks.svelte index c99f35d..2772eb7 100644 --- a/web/frontend/src/header/NavbarLinks.svelte +++ b/web/frontend/src/header/NavbarLinks.svelte @@ -24,39 +24,69 @@ {#each links as item} {#if item.listOptions} - - - - {item.title} - - - - All Clusters - - - {#each clusters as cluster} - - - {cluster.name} - - - - Running Jobs - - - - {/each} - - + {#if item.title === 'Nodes'} + + + + {item.title} + + + {#each clusters as cluster} + + + {cluster.name} + + + + Node Overview + + + Node List + + + + {/each} + + + {:else} + + + + {item.title} + + + + All Clusters + + + {#each clusters as cluster} + + + {cluster.name} + + + + Running Jobs + + + + {/each} + + + {/if} {:else if !item.perCluster} {item.title} + + + + +
+ + + + + {#if showFootprint} + + {/if} + {#each metrics as metric (metric)} + + {/each} + + + + {#if $jobsStore.error} + + + + {:else} + {#each jobs as job (job)} + + {:else} + + + + {/each} + {/if} + {#if $jobsStore.fetching || !$jobsStore.data} + + + + {/if} + +
+ Job Info + + Job Footprint + + {metric} + {#if $initialized} + ({getUnit(metric)}) + {/if} +
+

{$jobsStore.error.message}

+
No jobs found
+
+ +
+
+
+
+ +{#if usePaging} + { + if (detail.itemsPerPage != itemsPerPage) { + updateConfiguration(detail.itemsPerPage.toString(), detail.page); + } else { + jobs = [] + paging = { itemsPerPage: detail.itemsPerPage, page: detail.page }; + } + }} + /> +{/if} + + diff --git a/web/frontend/src/systems/NodeOverview.svelte b/web/frontend/src/systems/NodeOverview.svelte new file mode 100644 index 0000000..b5d1d0b --- /dev/null +++ b/web/frontend/src/systems/NodeOverview.svelte @@ -0,0 +1,232 @@ + + + + + + {#if $initq.error} + {$initq.error.message} + {:else if $initq.fetching} + + {:else} + + + + + Find Node + + + + + + + + + + + + Metric + + + + + + { + const diff = Date.now() - to; + from = new Date(from.getTime() + diff); + to = new Date(to.getTime() + diff); + }} + /> + + {/if} + +
+{#if $nodesQuery.error} + + + {$nodesQuery.error.message} + + +{:else if $nodesQuery.fetching || $initq.fetching} + + + + + +{:else} + + 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", + ), + disabled: checkMetricDisabled( + selectedMetric, + cluster, + h.subCluster, + ), + })) + .sort((a, b) => a.host.localeCompare(b.host))} + > +

+ {item.host} ({item.subCluster}) +

+ {#if item.disabled === false && item.data} + c.name == cluster)} + subCluster={item.subCluster} + forNode={true} + /> + {:else if item.disabled === true && item.data} + Metric disabled for subcluster {selectedMetric}:{item.subCluster} + {:else} + No dataset returned for {selectedMetric} + {/if} +
+{/if} diff --git a/web/frontend/src/systems/nodelist/NodeInfo.svelte b/web/frontend/src/systems/nodelist/NodeInfo.svelte new file mode 100644 index 0000000..0aee223 --- /dev/null +++ b/web/frontend/src/systems/nodelist/NodeInfo.svelte @@ -0,0 +1,152 @@ + + + + +
+

+ {job.jobId} + ({job.cluster}) + {#if job.metaData?.jobName} +
+ {#if job.metaData?.jobName.length <= 25} +

{job.metaData.jobName}
+ {:else} +
+ {job.metaData.jobName} +
+ {/if} + {/if} + {#if job.arrayJobId} + Array Job: #{job.arrayJobId} + {/if} +

+ +

+ + + {scrambleNames ? scramble(job.user) : job.user} + + {#if job.userData && job.userData.name} + ({scrambleNames ? scramble(job.userData.name) : job.userData.name}) + {/if} + {#if job.project && job.project != "no project"} +
+ + + {scrambleNames ? scramble(job.project) : job.project} + + {/if} +

+ +

+ {#if job.numNodes == 1} + {job.resources[0].hostname} + {:else} + {job.numNodes} + {/if} + + {#if job.exclusive != 1} + (shared) + {/if} + {#if job.numAcc > 0} + , {job.numAcc} + {/if} + {#if job.numHWThreads > 0} + , {job.numHWThreads} + {/if} +
+ {job.subCluster} +

+ +

+ Start: {new Date(job.startTime).toLocaleString()} +
+ Duration: {formatDuration(job.duration)} + {job.state} + {#if job.walltime} +
+ Walltime: {formatDuration(job.walltime)} + {/if} +

+ + {#if showTagedit} +
+

+ : + {#if jobTags?.length > 0} + {#each jobTags as tag} + + {/each} + {:else} + No Tags + {/if} +

+ {:else} +

+ {#each jobTags as tag} + + {/each} +

+ {/if} +
+ + diff --git a/web/frontend/src/systems/nodelist/NodeListRow.svelte b/web/frontend/src/systems/nodelist/NodeListRow.svelte new file mode 100644 index 0000000..1832a94 --- /dev/null +++ b/web/frontend/src/systems/nodelist/NodeListRow.svelte @@ -0,0 +1,207 @@ + + + + + + + + + {#if job.monitoringStatus == 0 || job.monitoringStatus == 2} + + Not monitored or archiving failed + + {:else if $metricsQuery.fetching} + + + + {:else if $metricsQuery.error} + + + {$metricsQuery.error.message.length > 500 + ? $metricsQuery.error.message.substring(0, 499) + "..." + : $metricsQuery.error.message} + + + {:else} + {#if showFootprint} + + + + {/if} + {#each sortAndSelectScope($metricsQuery.data.jobMetrics) as metric, i (metric || i)} + + + {#if metric.disabled == false && metric.data} + { handleZoom(detail, metric.data.name) }} + height={plotHeight} + timestep={metric.data.metric.timestep} + scope={metric.data.scope} + series={metric.data.metric.series} + statisticsSeries={metric.data.metric.statisticsSeries} + metric={metric.data.name} + {cluster} + subCluster={job.subCluster} + isShared={job.exclusive != 1} + numhwthreads={job.numHWThreads} + numaccs={job.numAcc} + zoomState={zoomStates[metric.data.name] || null} + /> + {:else if metric.disabled == true && metric.data} + Metric disabled for subcluster {metric.data.name}:{job.subCluster} + {:else} + No dataset returned + {/if} + + {/each} + {/if} + diff --git a/web/templates/monitoring/systems.tmpl b/web/templates/monitoring/systems.tmpl index 27bbf64..635bf46 100644 --- a/web/templates/monitoring/systems.tmpl +++ b/web/templates/monitoring/systems.tmpl @@ -7,6 +7,7 @@ {{end}} {{define "javascript"}}