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

For #681 - Changes to Violators and Deadweight pages and fetch calls … #695

Merged
merged 1 commit into from
Nov 21, 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
2 changes: 2 additions & 0 deletions code/dashboard-2/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ const router = createBrowserRouter(
<Route path=":clusterName/violators/:violator" element={<ViolatorPage/>}/>
<Route path=":clusterName/deadweight" element={<DeadWeightPage/>}/>
<Route path=":clusterName/:hostname" element={<HostDetailsPage/>}/>
<Route path=":clusterName/:hostname/violators" element={<ViolatorsPage/>}/>
<Route path=":clusterName/:hostname/:violator" element={<ViolatorPage/>}/>
<Route path=":clusterName/:hostname/deadweight" element={<DeadWeightPage/>}/>
<Route path="jobQuery" element={<JobQueryPage/>}/>
</Route>
)
Expand Down
8 changes: 4 additions & 4 deletions code/dashboard-2/src/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const PAGE_TITLE_SUFFIX = ' | ' + APP_NAME
// URLs and API Endpoints to be moved to .env files once dev and prod environments are set up
export const APP_URL = 'https://naic-monitor.uio.no'
export const API_ENDPOINT = import.meta.env.VITE_API_ENDPOINT
export const JOB_QUERY_API_ENDPOINT = import.meta.env.VITE_JOB_QUERY_API_ENDPOINT
export const QUERY_API_ENDPOINT = import.meta.env.VITE_QUERY_API_ENDPOINT

// The representation of "true" is a hack, but it's determined by the server, so live with it.
export const TRUE_VAL = 'xxxxxtruexxxxx'
Expand Down Expand Up @@ -134,8 +134,8 @@ export const CLUSTER_INFO: Record<string, Cluster> = {
canonical: 'mlx.hpc.uio.no',
subclusters: [{name: 'nvidia', nodes: 'ml[1-3,6-9]'}],
uptime: true,
violators: false,
deadweight: false,
violators: true,
deadweight: true,
defaultQuery: '*',
hasDowntime: true,
name: 'ML nodes',
Expand All @@ -154,7 +154,7 @@ export const CLUSTER_INFO: Record<string, Cluster> = {
],
uptime: true,
violators: false,
deadweight: false,
deadweight: true,
defaultQuery: 'login* or int*',
name: 'Fox',
hasDowntime: true,
Expand Down
4 changes: 2 additions & 2 deletions code/dashboard-2/src/hooks/useExportJobQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'
import { AxiosInstance } from 'axios'

import useAxios from './useAxios.ts'
import { JOB_QUERY_API_ENDPOINT, QueryKeys } from '../Constants.ts'
import { QUERY_API_ENDPOINT, QueryKeys } from '../Constants.ts'
import { prepareJobQueryString } from '../util/query/QueryUtils.ts'
import { ExportOptions, JobQueryValues } from '../types'

Expand All @@ -16,7 +16,7 @@ const exportJobQuery = async (axios: AxiosInstance, jobQueryValues: JobQueryValu
}

export const useExportJobQuery = (jobQueryValues: JobQueryValues, exportOptions: ExportOptions) => {
const axios = useAxios(JOB_QUERY_API_ENDPOINT)
const axios = useAxios(QUERY_API_ENDPOINT)
return useQuery(
{
enabled: false,
Expand Down
10 changes: 5 additions & 5 deletions code/dashboard-2/src/hooks/useFetchDeadWeight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'
import { AxiosInstance, AxiosResponse } from 'axios'

import useAxios from './useAxios.ts'
import { QueryKeys } from '../Constants.ts'
import { QUERY_API_ENDPOINT, QueryKeys } from '../Constants.ts'
import { prepareShareableJobQueryLink } from '../util/query/QueryUtils.ts'
import {
Cluster,
Expand All @@ -16,19 +16,19 @@ interface Filter {
hostname: string | null
}

const fetchDeadWeight = async (axios: AxiosInstance, canonical: string, clusterName: string) => {
const endpoint = `${canonical}/${clusterName}-deadweight-report.json`
const fetchDeadWeight = async (axios: AxiosInstance, clusterName: string) => {
const endpoint = `/report?cluster=${clusterName}&report-name=${clusterName}-deadweight-report.json`
const response: AxiosResponse<FetchedDeadWeight[]> = await axios.get(endpoint)
return response.data
}

export const useFetchDeadWeight = (cluster: Cluster, filter: Filter | null = null, enabled: boolean = true) => {
const axios = useAxios()
const axios = useAxios(QUERY_API_ENDPOINT)
return useQuery<FetchedDeadWeight[], Error, DeadWeight[]>(
{
enabled,
queryKey: [QueryKeys.DEAD_WEIGHT, cluster.cluster],
queryFn: () => fetchDeadWeight(axios, cluster.canonical, cluster.cluster),
queryFn: () => fetchDeadWeight(axios, cluster.cluster),
select: data => {
let deadWeights: DeadWeight[] = data.map((d: FetchedDeadWeight) => {
const commonJobQueryValues = {
Expand Down
4 changes: 2 additions & 2 deletions code/dashboard-2/src/hooks/useFetchJobQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'
import { AxiosInstance } from 'axios'

import useAxios from './useAxios.ts'
import { JOB_QUERY_API_ENDPOINT, QueryKeys } from '../Constants.ts'
import { QUERY_API_ENDPOINT, QueryKeys } from '../Constants.ts'
import {
FetchedJobQueryResultItem,
JobQueryJobId,
Expand All @@ -22,7 +22,7 @@ const fetchJobQuery = async (axios: AxiosInstance, jobQueryValues: JobQueryValue
}

export const useFetchJobQuery = (jobQueryValues: JobQueryValues, fields: string[]) => {
const axios = useAxios(JOB_QUERY_API_ENDPOINT)
const axios = useAxios(QUERY_API_ENDPOINT)
return useQuery<FetchedJobQueryResultItem[], Error, JobQueryResultsTableItem[]>(
{
enabled: false,
Expand Down
10 changes: 5 additions & 5 deletions code/dashboard-2/src/hooks/useFetchViolations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query'
import { AxiosInstance, AxiosResponse } from 'axios'

import useAxios from './useAxios.ts'
import { QueryKeys } from '../Constants.ts'
import { QUERY_API_ENDPOINT, QueryKeys } from '../Constants.ts'
import {
Cluster,
FetchedViolatingJob,
Expand All @@ -17,19 +17,19 @@ interface Filter {
hostname: string | null
}

const fetchViolations = async (axios: AxiosInstance, canonical: string, clusterName: string) => {
const endpoint = `${canonical}/${clusterName}-violator-report.json`
const fetchViolations = async (axios: AxiosInstance, clusterName: string) => {
const endpoint = `/report?cluster=${clusterName}&report-name=${clusterName}-violator-report.json`
const response: AxiosResponse<FetchedViolatingJob[]> = await axios.get(endpoint)
return response.data
}

export const useFetchViolations = (cluster: Cluster, filter: Filter | null = null, enabled: boolean = true) => {
const axios = useAxios()
const axios = useAxios(QUERY_API_ENDPOINT)
return useQuery(
{
enabled,
queryKey: [QueryKeys.VIOLATIONS, cluster.cluster],
queryFn: () => fetchViolations(axios, cluster.canonical, cluster.cluster),
queryFn: () => fetchViolations(axios, cluster.cluster),
select: (data) => {

let violatingJobs: ViolatingJob[] = data.map((d) => {
Expand Down
10 changes: 5 additions & 5 deletions code/dashboard-2/src/hooks/useFetchViolator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import { useQuery } from '@tanstack/react-query'
import { AxiosInstance, AxiosResponse } from 'axios'

import useAxios from './useAxios.ts'
import { POLICIES, QueryKeys } from '../Constants.ts'
import { QUERY_API_ENDPOINT, POLICIES, QueryKeys } from '../Constants.ts'
import { Cluster, FetchedViolatingJob } from '../types'

const fetchViolator = async (axios: AxiosInstance, canonical: string, clusterName: string) => {
const endpoint = `${canonical}/${clusterName}-violator-report.json`
const fetchViolator = async (axios: AxiosInstance, clusterName: string) => {
const endpoint = `/report?cluster=${clusterName}&report-name=${clusterName}-violator-report.json`
const response: AxiosResponse<FetchedViolatingJob[]> = await axios.get(endpoint)
return response.data
}

export const useFetchViolator = (cluster: Cluster, violator: string) => {
const axios = useAxios()
const axios = useAxios(QUERY_API_ENDPOINT)
return useQuery(
{
queryKey: [QueryKeys.VIOLATOR, cluster.cluster, violator],
queryFn: () => fetchViolator(axios, cluster.canonical, cluster.cluster),
queryFn: () => fetchViolator(axios, cluster.cluster),
select: (data) => {

const jobsOfUser = data.filter(job => job.user === violator)
Expand Down
15 changes: 11 additions & 4 deletions code/dashboard-2/src/pages/DeadWeightPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { useFetchDeadWeight } from '../hooks/useFetchDeadWeight.ts'


export default function DeadWeightPage() {
const {clusterName} = useParams<string>()
const {clusterName, hostname} = useParams<string>()

const cluster = findCluster(clusterName)

Expand All @@ -33,7 +33,12 @@ export default function DeadWeightPage() {
)
}

const {data, isFetched} = useFetchDeadWeight(cluster)
const filter = {
afterDate: null,
hostname: hostname || null
}

const {data, isFetched} = useFetchDeadWeight(cluster, filter)

const deadWeightJobTableColumns = useMemo(() => getDeadWeightTableColumns(), [cluster])
const [sorting, setSorting] = useState<SortingState>([])
Expand All @@ -49,13 +54,15 @@ export default function DeadWeightPage() {
}
})

const pageTitle = `${cluster.name} Deadweight${hostname ? ` - ${hostname}` : ''}`

return (
<>
<PageTitle title={`${cluster.name} Deadweight`}/>
<PageTitle title={pageTitle}/>
<VStack alignItems={'start'}>
<HStack mb={3}>
<NavigateBackButton/>
<Heading ml={2} size={{base: 'md', md: 'lg'}}>{cluster.name} dead weight</Heading>
<Heading ml={2} size={{base: 'md', md: 'lg'}}>{pageTitle}</Heading>
</HStack>
<Text mb={3}>
The following processes and jobs are zombies or defuncts or
Expand Down
139 changes: 23 additions & 116 deletions code/dashboard-2/src/pages/HostDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
import { useMemo, useState } from 'react'
import { useState } from 'react'
import {
Box,
Box, Button, ButtonGroup,
Checkbox,
Divider,
Heading,
HStack,
Link as ChakraLink,
Select,
SlideFade,
Spacer,
Text,
VStack
} from '@chakra-ui/react'
import { Link as ReactRouterLink, Navigate, useParams } from 'react-router-dom'
import { getCoreRowModel, getSortedRowModel, SortingState, useReactTable } from '@tanstack/react-table'

import { EMPTY_ARRAY, FETCH_FREQUENCIES } from '../Constants.ts'
import { FETCH_FREQUENCIES } from '../Constants.ts'
import { useFetchHostnames } from '../hooks/useFetchHosts.ts'
import { useFetchHostDetails } from '../hooks/useFetchHostDetails.ts'
import { useFetchViolations } from '../hooks/useFetchViolations.ts'
import { useFetchDeadWeight } from '../hooks/useFetchDeadWeight.ts'
import { findCluster } from '../util'
import {
getDeadWeightTableColumns,
getViolatingJobTableColumns,
getViolatingUserTableColumns
} from '../util/TableUtils.ts'
import { NavigateBackButton, PageTitle } from '../components'
import { ViolatingUserTable, ViolatingJobTable, DeadWeightTable } from '../components/table'
import { MachineDetailsChart } from '../components/chart/MachineDetailsChart'
import { IoSearchOutline } from 'react-icons/io5'
import { GiShamblingZombie } from 'react-icons/gi'
import { PiGavel } from 'react-icons/pi'


export default function HostDetailsPage() {
Expand Down Expand Up @@ -57,64 +49,9 @@ export default function HostDetailsPage() {
data: hostDetails
} = useFetchHostDetails(selectedCluster.canonical, hostname!, selectedFrequency.value, isShowData, isShowDowntime, isValidHostname)

const now = new Date()
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000)

const filter = {
afterDate: thirtyDaysAgo,
hostname: hostname,
}

const {
data: violations,
isFetched: isFetchedViolations,
} = useFetchViolations(selectedCluster, filter, isValidHostname)

const violatingUserTableColumns = useMemo(() => getViolatingUserTableColumns(), [selectedCluster])
const [violatingUserTableSorting, setViolatingUserTableSorting] = useState<SortingState>([])

const violatingUserTable = useReactTable({
columns: violatingUserTableColumns,
data: violations?.byUser || EMPTY_ARRAY,
getCoreRowModel: getCoreRowModel(),
onSortingChange: setViolatingUserTableSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting: violatingUserTableSorting,
}
})

const violatingJobTableColumns = useMemo(() => getViolatingJobTableColumns(), [selectedCluster])
const [violatingJobTableSorting, setViolatingJobTableSorting] = useState<SortingState>([])

const violatingJobTable = useReactTable({
columns: violatingJobTableColumns,
data: violations?.byJob || EMPTY_ARRAY,
getCoreRowModel: getCoreRowModel(),
onSortingChange: setViolatingJobTableSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting: violatingJobTableSorting,
}
})

const {data: deadweights, isFetched: isFetchedDeadweights} = useFetchDeadWeight(selectedCluster, filter, isValidHostname)

const deadWeightJobTableColumns = useMemo(() => getDeadWeightTableColumns(), [clusterName])
const [sorting, setSorting] = useState<SortingState>([])

const deadWeightTable = useReactTable({
columns: deadWeightJobTableColumns,
data: deadweights || EMPTY_ARRAY,
getCoreRowModel: getCoreRowModel(),
onSortingChange: setSorting,
getSortedRowModel: getSortedRowModel(),
state: {
sorting: sorting,
}
})

const jobQueryLink = `/jobquery?cluster=${clusterName}&host=${hostname}`
const violatorsLink = `/${clusterName}/${hostname}/violators`
const deadWeightLink = `/${clusterName}/${hostname}/deadweight`

return (
<>
Expand All @@ -128,10 +65,22 @@ export default function HostDetailsPage() {
</HStack>
<Text> Description :{'\t'}{hostDetails?.system.description}
</Text>
<ChakraLink as={ReactRouterLink} to={jobQueryLink}>
Job Query for this host
</ChakraLink>

<ButtonGroup size={'sm'} spacing="2" variant={'outline'}>
<Button as={ReactRouterLink} to={jobQueryLink} leftIcon={<IoSearchOutline/>}>
Job Query
</Button>
{selectedCluster.violators &&
<Button as={ReactRouterLink} to={violatorsLink} leftIcon={<PiGavel/>}>
View Violators
</Button>
}
{selectedCluster.deadweight &&
<Button as={ReactRouterLink} to={deadWeightLink} leftIcon={<GiShamblingZombie/>}>
View Zombies
</Button>
}
</ButtonGroup>
<Divider/>

<Heading as="h4" size="lg" my="0px">Machine Load</Heading>
Expand Down Expand Up @@ -195,48 +144,6 @@ export default function HostDetailsPage() {
measurement is the sum of the sizes of the jobs&apos; private memories.
</Text>

{selectedCluster.violators &&
<>
<Heading as="h4" size="lg" mt="20px">
Violators last 30 days
</Heading>

<Text>
The following jobs have violated usage policy and are probably not appropriate to run on this cluster. The
list
is recomputed at noon and midnight and goes back four weeks.
</Text>

<Heading as="h4" size="md">By user</Heading>

<SlideFade in={isFetchedViolations}>
<ViolatingUserTable table={violatingUserTable}/>
</SlideFade>
<Heading as="h4" size="md" mt="20px">
By job and time
</Heading>
<SlideFade in={isFetchedViolations}>
<ViolatingJobTable table={violatingJobTable}/>
</SlideFade>
</>
}

{selectedCluster.deadweight &&
<>
<Heading as="h4" size="lg" mt="20px">
Deadweight processes last 30 days
</Heading>
<Text>
The following processes and jobs are zombies or defuncts or
otherwise dead and may be bogging down the system. The list is
recomputed at noon and midnight and goes back four weeks.
</Text>

<SlideFade in={isFetchedDeadweights}>
<DeadWeightTable table={deadWeightTable}/>
</SlideFade>
</>
}
</VStack>
</>
)
Expand Down
Loading
Loading