Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix #268

Merged
merged 14 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions cmd/cc-backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ const configString = `
"kind": "file",
"path": "./var/job-archive"
},
"jwts": {
"max-age": "2000h"
},
"clusters": [
{
"name": "name",
Expand Down Expand Up @@ -115,15 +118,15 @@ func initEnv() {
os.Exit(0)
}

if err := os.WriteFile("config.json", []byte(configString), 0666); err != nil {
if err := os.WriteFile("config.json", []byte(configString), 0o666); err != nil {
log.Fatalf("Writing config.json failed: %s", err.Error())
}

if err := os.WriteFile(".env", []byte(envString), 0666); err != nil {
if err := os.WriteFile(".env", []byte(envString), 0o666); err != nil {
log.Fatalf("Writing .env failed: %s", err.Error())
}

if err := os.Mkdir("var", 0777); err != nil {
if err := os.Mkdir("var", 0o777); err != nil {
log.Fatalf("Mkdir var failed: %s", err.Error())
}

Expand Down
4 changes: 2 additions & 2 deletions internal/metricdata/metricdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ func LoadData(job *schema.Job,
jd, err = repo.LoadData(job, metrics, scopes, ctx)
if err != nil {
if len(jd) != 0 {
log.Errorf("partial error: %s", err.Error())
return err, 0, 0
log.Warnf("partial error: %s", err.Error())
// return err, 0, 0 // Reactivating will block archiving on one partial error
} else {
log.Error("Error while loading job data from metric repository")
return err, 0, 0
Expand Down
6 changes: 3 additions & 3 deletions internal/repository/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ func (r *JobRepository) archivingWorker() {
// not using meta data, called to load JobMeta into Cache?
// will fail if job meta not in repository
if _, err := r.FetchMetadata(job); err != nil {
log.Errorf("archiving job (dbid: %d) failed: %s", job.ID, err.Error())
log.Errorf("archiving job (dbid: %d) failed at check metadata step: %s", job.ID, err.Error())
r.UpdateMonitoringStatus(job.ID, schema.MonitoringStatusArchivingFailed)
continue
}
Expand All @@ -529,14 +529,14 @@ func (r *JobRepository) archivingWorker() {
// TODO: Maybe use context with cancel/timeout here
jobMeta, err := metricdata.ArchiveJob(job, context.Background())
if err != nil {
log.Errorf("archiving job (dbid: %d) failed: %s", job.ID, err.Error())
log.Errorf("archiving job (dbid: %d) failed at archiving job step: %s", job.ID, err.Error())
r.UpdateMonitoringStatus(job.ID, schema.MonitoringStatusArchivingFailed)
continue
}

// Update the jobs database entry one last time:
if err := r.MarkArchived(job.ID, schema.MonitoringStatusArchivingSuccessful, jobMeta.Statistics); err != nil {
log.Errorf("archiving job (dbid: %d) failed: %s", job.ID, err.Error())
log.Errorf("archiving job (dbid: %d) failed at marking archived step: %s", job.ID, err.Error())
continue
}
log.Debugf("archiving job %d took %s", job.JobID, time.Since(start))
Expand Down
3 changes: 3 additions & 0 deletions internal/repository/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,9 @@ func buildStringCondition(field string, cond *model.StringInput, query sq.Select
}

func buildMetaJsonCondition(jsonField string, cond *model.StringInput, query sq.SelectBuilder) sq.SelectBuilder {
// Verify and Search Only in Valid Jsons
query = query.Where("JSON_VALID(meta_data)")
// add "AND" Sql query Block for field match
if cond.Eq != nil {
return query.Where("JSON_EXTRACT(meta_data, \"$."+jsonField+"\") = ?", *cond.Eq)
}
Expand Down
18 changes: 15 additions & 3 deletions internal/routerConfig/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,11 +302,19 @@ func HandleSearchBar(rw http.ResponseWriter, r *http.Request, buildInfo web.Buil
case "jobId":
http.Redirect(rw, r, "/monitoring/jobs/?jobId="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery
case "jobName":
http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery
// Add Last 30 Days to migitate timeouts
untilTime := strconv.FormatInt(time.Now().Unix(), 10)
fromTime := strconv.FormatInt((time.Now().Unix() - int64(30*24*3600)), 10)

http.Redirect(rw, r, "/monitoring/jobs/?startTime="+fromTime+"-"+untilTime+"&jobName="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery
case "projectId":
http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery
case "arrayJobId":
http.Redirect(rw, r, "/monitoring/jobs/?arrayJobId="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery
// Add Last 30 Days to migitate timeouts
untilTime := strconv.FormatInt(time.Now().Unix(), 10)
fromTime := strconv.FormatInt((time.Now().Unix() - int64(30*24*3600)), 10)

http.Redirect(rw, r, "/monitoring/jobs/?startTime="+fromTime+"-"+untilTime+"&arrayJobId="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound) // All Users: Redirect to Tablequery
case "username":
if user.HasAnyRole([]schema.Role{schema.RoleAdmin, schema.RoleSupport, schema.RoleManager}) {
http.Redirect(rw, r, "/monitoring/users/?user="+url.QueryEscape(strings.Trim(splitSearch[1], " ")), http.StatusFound)
Expand Down Expand Up @@ -339,7 +347,11 @@ func HandleSearchBar(rw http.ResponseWriter, r *http.Request, buildInfo web.Buil
} else if project != "" {
http.Redirect(rw, r, "/monitoring/jobs/?projectMatch=eq&project="+url.QueryEscape(project), http.StatusFound) // projectId (equal)
} else if jobname != "" {
http.Redirect(rw, r, "/monitoring/jobs/?jobName="+url.QueryEscape(jobname), http.StatusFound) // JobName (contains)
// Add Last 30 Days to migitate timeouts
untilTime := strconv.FormatInt(time.Now().Unix(), 10)
fromTime := strconv.FormatInt((time.Now().Unix() - int64(30*24*3600)), 10)

http.Redirect(rw, r, "/monitoring/jobs/?startTime="+fromTime+"-"+untilTime+"&jobName="+url.QueryEscape(jobname), http.StatusFound) // 30D Fitler + JobName (contains)
} else {
web.RenderTemplate(rw, "message.tmpl", &web.Page{Title: "Info", MsgType: "alert-info", Message: "Search without result", User: *user, Roles: availableRoles, Build: buildInfo})
}
Expand Down
6 changes: 2 additions & 4 deletions web/frontend/src/Job.root.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,11 @@
.find((c) => c.name == job.cluster)
.metricConfig.map((mc) => mc.name);

// Metric not found in JobMetrics && Metric not explicitly disabled: Was expected, but is Missing
// Metric not found in JobMetrics && Metric not explicitly disabled in config or deselected: Was expected, but is Missing
missingMetrics = metricNames.filter(
(metric) =>
!metrics.some((jm) => jm.name == metric) &&
selectedMetrics.includes(metric) &&
!checkMetricDisabled(
metric,
$initq.data.job.cluster,
Expand Down Expand Up @@ -306,9 +307,6 @@
</Button>
{/if}
</Col>
<!-- <Col xs="auto">
<Zoom timeseriesPlots={plots} />
</Col> -->
</Row>
<Row>
<Col>
Expand Down
6 changes: 4 additions & 2 deletions web/frontend/src/Jobs.root.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import Refresher from "./joblist/Refresher.svelte";
import Sorting from "./joblist/SortSelection.svelte";
import MetricSelection from "./MetricSelection.svelte";
import UserOrProject from "./filters/UserOrProject.svelte";
import TextFilter from "./filters/TextFilter.svelte";

const { query: initq } = init();

Expand All @@ -38,6 +38,7 @@
? !!ccconfig[`plot_list_showFootprint:${filterPresets.cluster}`]
: !!ccconfig.plot_list_showFootprint;
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null;
let presetProject = filterPresets?.project ? filterPresets.project : ""

// The filterPresets are handled by the Filters component,
// so we need to wait for it to be ready before we can start a query.
Expand Down Expand Up @@ -86,7 +87,8 @@
</Col>

<Col xs="3" style="margin-left: auto;">
<UserOrProject
<TextFilter
{presetProject}
bind:authlevel
bind:roles
on:update={({ detail }) => filterComponent.update(detail)}
Expand Down
37 changes: 33 additions & 4 deletions web/frontend/src/Metric.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,17 @@
error = null;
let selectedScope = minScope(scopes);

let statsPattern = /(.*)-stats$/
let statsSeries = rawData.map((data) => data?.statisticsSeries ? data.statisticsSeries : null)
let selectedScopeIndex

$: availableScopes = scopes;
$: selectedScopeIndex = scopes.findIndex((s) => s == selectedScope);
$: patternMatches = statsPattern.exec(selectedScope)
$: if (!patternMatches) {
selectedScopeIndex = scopes.findIndex((s) => s == selectedScope);
} else {
selectedScopeIndex = scopes.findIndex((s) => s == patternMatches[1]);
}
$: data = rawData[selectedScopeIndex];
$: series = data?.series.filter(
(series) => selectedHost == null || series.hostname == selectedHost,
Expand Down Expand Up @@ -62,6 +71,7 @@
if (jm.scope != "node") {
scopes = [...scopes, jm.scope];
rawData.push(jm.metric);
statsSeries = rawData.map((data) => data?.statisticsSeries ? data.statisticsSeries : null)
selectedScope = jm.scope;
selectedScopeIndex = scopes.findIndex((s) => s == jm.scope);
dispatch("more-loaded", jm);
Expand All @@ -79,15 +89,18 @@
: "") + (metricConfig?.unit?.base ? metricConfig.unit.base : "")})
</InputGroupText>
<select class="form-select" bind:value={selectedScope}>
{#each availableScopes as scope}
{#each availableScopes as scope, index}
<option value={scope}>{scope}</option>
{#if statsSeries[index]}
<option value={scope + '-stats'}>stats series ({scope})</option>
{/if}
{/each}
{#if availableScopes.length == 1 && metricConfig?.scope != "node"}
<option value={"load-more"}>Load more...</option>
{/if}
</select>
{#if job.resources.length > 1}
<select class="form-select" bind:value={selectedHost}>
<select class="form-select" bind:value={selectedHost} disabled={patternMatches}>
<option value={null}>All Hosts</option>
{#each job.resources as { hostname }}
<option value={hostname}>{hostname}</option>
Expand All @@ -100,7 +113,21 @@
<Spinner />
{:else if error != null}
<Card body color="danger">{error.message}</Card>
{:else if series != null}
{:else if series != null && !patternMatches}
<Timeseries
bind:this={plot}
{width}
height={300}
{cluster}
{subCluster}
timestep={data.timestep}
scope={selectedScope}
metric={metricName}
{series}
{isShared}
resources={job.resources}
/>
{:else if statsSeries[selectedScopeIndex] != null && patternMatches}
<Timeseries
bind:this={plot}
{width}
Expand All @@ -113,6 +140,8 @@
{series}
{isShared}
resources={job.resources}
statisticsSeries={statsSeries[selectedScopeIndex]}
useStatsSeries={!!statsSeries[selectedScopeIndex]}
/>
{/if}
{/key}
44 changes: 23 additions & 21 deletions web/frontend/src/Status.root.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -315,20 +315,11 @@

<!-- Loading indicator & Refresh -->

<Row cols={3}>
<Col xs="auto" style="align-self: flex-end;">
<Row cols={{ lg: 3, md: 3, sm: 1 }}>
<Col style="">
<h4 class="mb-0">Current utilization of cluster "{cluster}"</h4>
</Col>
<Col xs="auto" style="margin-left: 0.25rem;">
{#if $initq.fetching || $mainQuery.fetching}
<Spinner />
{:else if $initq.error}
<Card body color="danger">{$initq.error.message}</Card>
{:else}
<!-- ... -->
{/if}
</Col>
<Col xs="auto" style="margin-left: auto;">
<Col class="mt-2 mt-md-0 text-md-end">
<Button
outline
color="secondary"
Expand All @@ -337,7 +328,7 @@
<Icon name="bar-chart-line" /> Select Histograms
</Button>
</Col>
<Col xs="auto" style="margin-left: 0.25rem;">
<Col class="mt-2 mt-md-0">
<Refresher
initially={120}
on:reload={() => {
Expand All @@ -347,6 +338,17 @@
/>
</Col>
</Row>
<Row cols={1} class="text-center mt-3">
<Col>
{#if $initq.fetching || $mainQuery.fetching}
<Spinner />
{:else if $initq.error}
<Card body color="danger">{$initq.error.message}</Card>
{:else}
<!-- ... -->
{/if}
</Col>
</Row>
{#if $mainQuery.error}
<Row cols={1}>
<Col>
Expand All @@ -361,8 +363,8 @@

{#if $initq.data && $mainQuery.data}
{#each $initq.data.clusters.find((c) => c.name == cluster).subClusters as subCluster, i}
<Row cols={2} class="mb-3 justify-content-center">
<Col md="4" class="px-3">
<Row cols={{ lg: 2, md: 1 , sm: 1}} class="mb-3 justify-content-center">
<Col class="px-3">
<Card class="h-auto mt-1">
<CardHeader>
<CardTitle class="mb-0">SubCluster "{subCluster.name}"</CardTitle>
Expand Down Expand Up @@ -433,7 +435,7 @@
</CardBody>
</Card>
</Col>
<Col class="px-3">
<Col class="px-3 mt-2 mt-lg-0">
<div bind:clientWidth={plotWidths[i]}>
{#key $mainQuery.data.nodeMetrics}
<Roofline
Expand All @@ -457,7 +459,7 @@

<!-- Usage Stats as Histograms -->

<Row cols={4}>
<Row cols={{ lg: 4, md: 2, sm: 1 }}>
<Col class="p-2">
<div bind:clientWidth={colWidth1}>
<h4 class="text-center">
Expand Down Expand Up @@ -580,7 +582,7 @@
</Col>
</Row>
<hr class="my-2" />
<Row cols={2}>
<Row cols={{ lg: 2, md: 1 }}>
<Col class="p-2">
<div bind:clientWidth={colWidth2}>
{#key $mainQuery.data.stats}
Expand Down Expand Up @@ -610,7 +612,7 @@
{/key}
</Col>
</Row>
<Row cols={2}>
<Row cols={{ lg: 2, md: 1 }}>
<Col class="p-2">
<div bind:clientWidth={colWidth2}>
{#key $mainQuery.data.stats}
Expand Down Expand Up @@ -642,15 +644,15 @@
</Row>
<hr class="my-2" />
{#if metricsInHistograms}
<Row>
<Row cols={1}>
<Col>
{#key $mainQuery.data.stats[0].histMetrics}
<PlotTable
let:item
let:width
renderFor="user"
items={$mainQuery.data.stats[0].histMetrics}
itemsPerRow={3}
itemsPerRow={2}
>
<Histogram
data={convert2uplot(item.data)}
Expand Down
6 changes: 6 additions & 0 deletions web/frontend/src/User.root.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
} from "@sveltestrap/sveltestrap";
import { queryStore, gql, getContextClient } from "@urql/svelte";
import Filters from "./filters/Filters.svelte";
import TextFilter from "./filters/TextFilter.svelte"
import JobList from "./joblist/JobList.svelte";
import Sorting from "./joblist/SortSelection.svelte";
import Refresher from "./joblist/Refresher.svelte";
Expand Down Expand Up @@ -132,6 +133,11 @@
/>
</Col>
<Col xs="auto" style="margin-left: auto;">
<TextFilter
on:update={({ detail }) => filterComponent.update(detail)}
/>
</Col>
<Col xs="auto">
<Refresher on:reload={() => jobList.refresh()} />
</Col>
</Row>
Expand Down
2 changes: 1 addition & 1 deletion web/frontend/src/config/admin/ShowUsersRow.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<td>{user.username}</td>
<td>{user.name}</td>
<td>{user.projects}</td>
<td style="max-width: 200px;">{user.projects}</td>
<td>{user.email}</td>
<td><code>{user?.roles ? user.roles.join(", ") : "No Roles"}</code></td>
<td>
Expand Down
3 changes: 2 additions & 1 deletion web/frontend/src/filters/Filters.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@
opts.push(`userMatch=${filters.userMatch}`);
if (filters.project) opts.push(`project=${filters.project}`);
if (filters.jobName) opts.push(`jobName=${filters.jobName}`);
if (filters.projectMatch != "contains")
if (filters.arrayJobId) opts.push(`arrayJobId=${filters.arrayJobId}`);
if (filters.project && filters.projectMatch != "contains")
opts.push(`projectMatch=${filters.projectMatch}`);

if (opts.length == 0 && window.location.search.length <= 1) return;
Expand Down
Loading
Loading