Merge branch '15317-metrics'
[arvados.git] / services / workbench2 / src / views / process-panel / process-resource-card.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import React from 'react';
6 import {
7     StyleRulesCallback,
8     WithStyles,
9     withStyles,
10     Card,
11     CardHeader,
12     IconButton,
13     CardContent,
14     Tooltip,
15     Typography,
16     Grid,
17     Link,
18     Button
19 } from '@material-ui/core';
20 import { ArvadosTheme } from 'common/custom-theme';
21 import {
22     CloseIcon,
23     MaximizeIcon,
24     ResourceIcon,
25     UnMaximizeIcon,
26     ShowChartIcon,
27 } from 'components/icon/icon';
28 import { MPVPanelProps } from 'components/multi-panel-view/multi-panel-view';
29 import { connect } from 'react-redux';
30 import { Process } from 'store/processes/process';
31 import { NodeInstanceType } from 'store/process-panel/process-panel';
32 import { DetailsAttribute } from "components/details-attribute/details-attribute";
33 import { formatFileSize } from "common/formatters";
34 import { MountKind } from 'models/mount-types';
35
36 interface ProcessResourceCardDataProps {
37     process: Process;
38     nodeInfo: NodeInstanceType | null;
39     usageReport: string | null;
40 }
41
42 type CssRules = "card" | "header" | "title" | "avatar" | "iconHeader" | "content" | "sectionH3" | "reportButton";
43
44 const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
45     card: {
46         height: '100%'
47     },
48     header: {
49         paddingBottom: "0px"
50     },
51     title: {
52         paddingTop: theme.spacing.unit * 0.5
53     },
54     avatar: {
55         paddingTop: theme.spacing.unit * 0.5
56     },
57     iconHeader: {
58         fontSize: '1.875rem',
59         color: theme.customs.colors.greyL,
60     },
61     content: {
62         paddingTop: "0px",
63         maxHeight: `calc(100% - ${theme.spacing.unit * 7.5}px)`,
64         overflow: "auto"
65     },
66     sectionH3: {
67         margin: "0.5em",
68         color: theme.customs.colors.greyD,
69         fontSize: "0.8125rem",
70         textTransform: "uppercase",
71     },
72     reportButton: {
73     }
74 });
75
76 type ProcessResourceCardProps = ProcessResourceCardDataProps & WithStyles<CssRules> & MPVPanelProps;
77
78 export const ProcessResourceCard = withStyles(styles)(connect()(
79     ({ classes, nodeInfo, usageReport, doHidePanel, doMaximizePanel, doUnMaximizePanel, panelMaximized, panelName, process, }: ProcessResourceCardProps) => {
80         let diskRequest = 0;
81         if (process.container?.mounts) {
82             for (const mnt in process.container.mounts) {
83                 const mp = process.container.mounts[mnt];
84                 if (mp.kind === MountKind.TEMPORARY_DIRECTORY) {
85                     diskRequest += mp.capacity;
86                 }
87             }
88         }
89
90         return <Card className={classes.card} data-cy="process-resources-card">
91             <CardHeader
92                 className={classes.header}
93                 classes={{
94                     content: classes.title,
95                     avatar: classes.avatar,
96                 }}
97                 avatar={<ResourceIcon className={classes.iconHeader} />}
98                 title={
99                     <Typography noWrap variant='h6' color='inherit'>
100                         Resources
101                     </Typography>
102                 }
103                 action={
104                     <div>
105                         {usageReport && <Link href={usageReport} className={classes.reportButton} target="_blank"><ShowChartIcon /> Resource usage report</Link>}
106                         {doUnMaximizePanel && panelMaximized &&
107                             <Tooltip title={`Unmaximize ${panelName || 'panel'}`} disableFocusListener>
108                                 <IconButton onClick={doUnMaximizePanel}><UnMaximizeIcon /></IconButton>
109                             </Tooltip>}
110                         {doMaximizePanel && !panelMaximized &&
111                             <Tooltip title={`Maximize ${panelName || 'panel'}`} disableFocusListener>
112                                 <IconButton onClick={doMaximizePanel}><MaximizeIcon /></IconButton>
113                             </Tooltip>}
114                         {doHidePanel &&
115                             <Tooltip title={`Close ${panelName || 'panel'}`} disableFocusListener>
116                                 <IconButton disabled={panelMaximized} onClick={doHidePanel}><CloseIcon /></IconButton>
117                             </Tooltip>}
118                     </div>
119                 } />
120             <CardContent className={classes.content}>
121                 <Grid container>
122                     <Grid item xs={4}>
123                         <h3 className={classes.sectionH3}>Requested Resources</h3>
124                         <Grid container>
125                             <Grid item xs={12}>
126                                 <DetailsAttribute label="Cores" value={process.container?.runtimeConstraints.vcpus} />
127                             </Grid>
128                             <Grid item xs={12}>
129                                 <DetailsAttribute label="RAM*" value={formatFileSize(process.container?.runtimeConstraints.ram)} />
130                             </Grid>
131                             <Grid item xs={12}>
132                                 <DetailsAttribute label="Disk" value={formatFileSize(diskRequest)} />
133                             </Grid>
134
135                             {process.container?.runtimeConstraints.cuda &&
136                                 process.container?.runtimeConstraints.cuda.device_count > 0 ?
137                                 <>
138                                     <Grid item xs={12}>
139                                         <DetailsAttribute label="CUDA devices" value={process.container?.runtimeConstraints.cuda.device_count} />
140                                     </Grid>
141                                     <Grid item xs={12}>
142                                         <DetailsAttribute label="CUDA driver version" value={process.container?.runtimeConstraints.cuda.driver_version} />
143                                     </Grid>
144                                     <Grid item xs={12}>
145                                         <DetailsAttribute label="CUDA hardware capability" value={process.container?.runtimeConstraints.cuda.hardware_capability} />
146                                     </Grid>
147                                 </> : null}
148
149                             {process.container?.runtimeConstraints.keep_cache_ram &&
150                                 process.container?.runtimeConstraints.keep_cache_ram > 0 ?
151                                 <Grid item xs={12}>
152                                     <DetailsAttribute label="Keep cache (RAM)" value={formatFileSize(process.container?.runtimeConstraints.keep_cache_ram)} />
153                                 </Grid> : null}
154
155                             {process.container?.runtimeConstraints.keep_cache_disk &&
156                                 process.container?.runtimeConstraints.keep_cache_disk > 0 ?
157                                 <Grid item xs={12}>
158                                     <DetailsAttribute label="Keep cache (disk)" value={formatFileSize(process.container?.runtimeConstraints.keep_cache_disk)} />
159                                 </Grid> : null}
160
161                             {process.container?.runtimeConstraints.API ? <Grid item xs={12}>
162                                 <DetailsAttribute label="API access" value={process.container?.runtimeConstraints.API.toString()} />
163                             </Grid> : null}
164
165                         </Grid>
166                     </Grid>
167
168
169                     <Grid item xs={8}>
170                         <h3 className={classes.sectionH3}>Assigned Instance Type</h3>
171                         {nodeInfo === null ? <Grid item xs={8}>
172                             No instance type recorded
173                         </Grid>
174                             :
175                             <Grid container>
176                                 <Grid item xs={6}>
177                                     <DetailsAttribute label="Cores" value={nodeInfo.VCPUs} />
178                                 </Grid>
179
180                                 <Grid item xs={6}>
181                                     <DetailsAttribute label="Provider type" value={nodeInfo.ProviderType} />
182                                 </Grid>
183
184                                 <Grid item xs={6}>
185                                     <DetailsAttribute label="RAM" value={formatFileSize(nodeInfo.RAM)} />
186                                 </Grid>
187
188                                 <Grid item xs={6}>
189                                     <DetailsAttribute label="Price" value={"$" + nodeInfo.Price.toString()} />
190                                 </Grid>
191
192                                 <Grid item xs={6}>
193                                     <DetailsAttribute label="Disk" value={formatFileSize(nodeInfo.IncludedScratch + nodeInfo.AddedScratch)} />
194                                 </Grid>
195
196                                 <Grid item xs={6}>
197                                     <DetailsAttribute label="Preemptible" value={nodeInfo.Preemptible.toString()} />
198                                 </Grid>
199
200                                 {nodeInfo.CUDA && nodeInfo.CUDA.DeviceCount > 0 &&
201                                     <>
202                                         <Grid item xs={6}>
203                                             <DetailsAttribute label="CUDA devices" value={nodeInfo.CUDA.DeviceCount} />
204                                         </Grid>
205
206                                         <Grid item xs={6}>
207                                         </Grid>
208
209                                         <Grid item xs={6}>
210                                             <DetailsAttribute label="CUDA driver version" value={nodeInfo.CUDA.DriverVersion} />
211                                         </Grid>
212
213                                         <Grid item xs={6}>
214                                         </Grid>
215
216                                         <Grid item xs={6}>
217                                             <DetailsAttribute label="CUDA hardware capability" value={nodeInfo.CUDA.HardwareCapability} />
218                                         </Grid>
219                                     </>
220                                 }
221                             </Grid>}
222                     </Grid>
223                 </Grid>
224                 <Typography>* RAM available to the program is limited to Requested RAM, not Instance RAM</Typography>
225             </CardContent>
226         </Card >;
227     }
228 ));