Skip to content

Commit 3cf53ef

Browse files
committed
Finalise Provisioner Warnings for Templates and template versions
1 parent a3eeb9c commit 3cf53ef

File tree

8 files changed

+270
-117
lines changed

8 files changed

+270
-117
lines changed

site/src/api/queries/organizations.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,17 @@ export const organizations = () => {
115115
};
116116
};
117117

118-
export const getProvisionerDaemonsKey = (organization: string) => [
118+
export const getProvisionerDaemonsKey = (organization: string, tags?: Record<string, string>) => [
119119
"organization",
120120
organization,
121+
tags,
121122
"provisionerDaemons",
122123
];
123124

124-
export const provisionerDaemons = (organization: string) => {
125+
export const provisionerDaemons = (organization: string, tags?: Record<string, string>) => {
125126
return {
126-
queryKey: getProvisionerDaemonsKey(organization),
127-
queryFn: () => API.getProvisionerDaemonsByOrganization(organization),
127+
queryKey: getProvisionerDaemonsKey(organization, tags),
128+
queryFn: () => API.getProvisionerDaemonsByOrganization(organization, tags),
128129
};
129130
};
130131

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Alert, AlertColor, AlertTitle } from "@mui/material";
2+
import { AlertDetail } from "components/Alert/Alert";
3+
import { type FC } from "react";
4+
5+
type ProvisionerAlertProps = {
6+
title: string,
7+
detail: string,
8+
severity: AlertColor,
9+
}
10+
11+
export const ProvisionerAlert : FC<ProvisionerAlertProps> = ({
12+
title,
13+
detail,
14+
severity,
15+
}) => {
16+
return (
17+
<Alert
18+
severity={severity}
19+
css={(theme) => ({
20+
borderRadius: 0,
21+
border: 0,
22+
borderBottom: `1px solid ${theme.palette.divider}`,
23+
borderLeft: `2px solid ${theme.palette.error.main}`,
24+
})}
25+
>
26+
<AlertTitle>{title}</AlertTitle>
27+
<AlertDetail>{detail}</AlertDetail>
28+
</Alert>
29+
);
30+
};

site/src/modules/provisioners/useCompatibleProvisioners.ts

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,4 @@
1-
import { API } from "api/api";
21
import { ProvisionerDaemon } from "api/typesGenerated";
3-
import { useEffect, useState } from "react";
4-
5-
export const useCompatibleProvisioners = (organization: string | undefined, tags: Record<string, string> | undefined) => {
6-
const [compatibleProvisioners, setCompatibleProvisioners] = useState<ProvisionerDaemon[]>([])
7-
8-
useEffect(() => {
9-
(async () => {
10-
if (!organization) {
11-
setCompatibleProvisioners([])
12-
return
13-
}
14-
15-
try {
16-
const provisioners = await API.getProvisionerDaemonsByOrganization(
17-
organization,
18-
tags,
19-
);
20-
21-
setCompatibleProvisioners(provisioners);
22-
} catch (error) {
23-
setCompatibleProvisioners([])
24-
}
25-
})();
26-
}, [organization, tags])
27-
28-
return compatibleProvisioners
29-
}
302

313
export const provisionersUnhealthy = (provisioners : ProvisionerDaemon[]) => {
324
return provisioners.reduce((allUnhealthy, provisioner) => {

site/src/pages/CreateTemplatePage/BuildLogsDrawer.stories.tsx

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
MockTemplateVersion,
66
MockWorkspaceBuildLogs,
77
} from "testHelpers/entities";
8-
import { withWebSocket } from "testHelpers/storybook";
8+
import { withProvisioners, withWebSocket } from "testHelpers/storybook";
99
import { BuildLogsDrawer } from "./BuildLogsDrawer";
1010

1111
const meta: Meta<typeof BuildLogsDrawer> = {
@@ -34,6 +34,51 @@ export const MissingVariables: Story = {
3434
},
3535
};
3636

37+
export const NoProvisioners: Story = {
38+
args: {
39+
templateVersion: {...MockTemplateVersion, organization_id: "org-id"},
40+
},
41+
decorators: [withProvisioners],
42+
parameters: {
43+
organization_id: "org-id",
44+
tags: MockTemplateVersion.job.tags,
45+
provisioners: [],
46+
}
47+
};
48+
49+
export const ProvisionersUnhealthy: Story = {
50+
args: {
51+
templateVersion: {...MockTemplateVersion, organization_id: "org-id"},
52+
},
53+
decorators: [withProvisioners],
54+
parameters: {
55+
organization_id: "org-id",
56+
tags: MockTemplateVersion.job.tags,
57+
provisioners: [
58+
{
59+
last_seen_at: new Date(new Date().getTime() - 5 * 60 * 1000).toISOString()
60+
},
61+
],
62+
}
63+
};
64+
65+
export const ProvisionersHealthy: Story = {
66+
args: {
67+
templateVersion: {...MockTemplateVersion, organization_id: "org-id"},
68+
},
69+
decorators: [withProvisioners],
70+
parameters: {
71+
organization_id: "org-id",
72+
tags: MockTemplateVersion.job.tags,
73+
provisioners: [
74+
{
75+
last_seen_at: new Date()
76+
},
77+
],
78+
}
79+
};
80+
81+
3782
export const Logs: Story = {
3883
args: {
3984
templateVersion: {

site/src/pages/CreateTemplatePage/BuildLogsDrawer.tsx

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Interpolation, Theme } from "@emotion/react";
1+
import { type Interpolation, type Theme } from "@emotion/react";
22
import Close from "@mui/icons-material/Close";
33
import WarningOutlined from "@mui/icons-material/WarningOutlined";
44
import Button from "@mui/material/Button";
@@ -12,9 +12,10 @@ import { useWatchVersionLogs } from "modules/templates/useWatchVersionLogs";
1212
import { WorkspaceBuildLogs } from "modules/workspaces/WorkspaceBuildLogs/WorkspaceBuildLogs";
1313
import { type FC, useLayoutEffect, useRef } from "react";
1414
import { navHeight } from "theme/constants";
15-
import { provisionersUnhealthy, useCompatibleProvisioners } from "modules/provisioners/useCompatibleProvisioners";
16-
import { Alert, AlertTitle } from "@mui/material";
17-
import { AlertDetail } from "components/Alert/Alert";
15+
import { provisionersUnhealthy } from "modules/provisioners/useCompatibleProvisioners";
16+
import { useQuery } from "react-query";
17+
import { provisionerDaemons } from "api/queries/organizations";
18+
import { ProvisionerAlert } from "modules/provisioners/ProvisionerAlert";
1819

1920
type BuildLogsDrawerProps = {
2021
error: unknown;
@@ -30,11 +31,15 @@ export const BuildLogsDrawer: FC<BuildLogsDrawerProps> = ({
3031
variablesSectionRef,
3132
...drawerProps
3233
}) => {
33-
const compatibleProvisioners = useCompatibleProvisioners(
34-
templateVersion?.organization_id,
35-
templateVersion?.job.tags
34+
const org = templateVersion?.organization_id
35+
const {
36+
data: compatibleProvisioners,
37+
isLoading: provisionerDaemonsLoading,
38+
isError: couldntGetProvisioners,
39+
} = useQuery(
40+
org ? provisionerDaemons(org, templateVersion?.job.tags) : { enabled: false}
3641
);
37-
const compatibleProvisionersUnhealthy = provisionersUnhealthy(compatibleProvisioners);
42+
const compatibleProvisionersUnhealthy = !compatibleProvisioners || provisionersUnhealthy(compatibleProvisioners);
3843

3944
const logs = useWatchVersionLogs(templateVersion);
4045
const logsContainer = useRef<HTMLDivElement>(null);
@@ -74,35 +79,26 @@ export const BuildLogsDrawer: FC<BuildLogsDrawerProps> = ({
7479
</IconButton>
7580
</header>
7681

77-
{ !compatibleProvisioners && !logs ? (
78-
// If there are no compatible provisioners, warn that this job may be stuck
79-
<Alert
80-
severity="warning"
81-
css={{
82-
borderRadius: 0,
83-
border: 0,
84-
// borderBottom: `1px solid ${theme.palette.divider}`,
85-
// borderLeft: `2px solid ${theme.palette.error.main}`,
86-
}}
87-
>
88-
<AlertTitle>Build stuck</AlertTitle>
89-
<AlertDetail>No Compatible Provisioner Daemons have been configured</AlertDetail>
90-
</Alert>
91-
) : compatibleProvisionersUnhealthy && !logs && (
92-
// If there are compatible provisioners in the db, but they have not reported recent health checks,
93-
// warn that the job might be stuck
94-
<Alert
95-
severity="warning"
96-
css={{
97-
borderRadius: 0,
98-
border: 0,
99-
// borderBottom: `1px solid ${theme.palette.divider}`,
100-
// borderLeft: `2px solid ${theme.palette.error.main}`,
101-
}}
102-
>
103-
<AlertTitle>Build may be delayed</AlertTitle>
104-
<AlertDetail>Compatible Provisioner Daemons have been silent for a while. This may result in a delayed build</AlertDetail>
105-
</Alert>
82+
{ !logs && !provisionerDaemonsLoading && (
83+
couldntGetProvisioners ? (
84+
<ProvisionerAlert
85+
severity="warning"
86+
title="Something went wrong"
87+
detail="Could not determine provisioner status. Your template build may fail. If your template does not build, please contact your administrator"
88+
/>
89+
) : (!compatibleProvisioners || compatibleProvisioners.length == 0) ? (
90+
<ProvisionerAlert
91+
severity="warning"
92+
title="Template Creation Stuck"
93+
detail="This organization does not have any provisioners to process this template. Configure a provisioner."
94+
/>
95+
) : compatibleProvisionersUnhealthy && (
96+
<ProvisionerAlert
97+
severity="warning"
98+
title="Template Creation Delayed"
99+
detail="Provisioners are currently unresponsive. This may delay your template creation. Please contact your administrator for support."
100+
/>
101+
)
106102
)}
107103

108104
{isMissingVariables ? (

site/src/pages/TemplateVersionEditorPage/TemplateVersionEditor.stories.tsx

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
MockWorkspaceResourceSensitive,
1717
MockWorkspaceVolumeResource,
1818
} from "testHelpers/entities";
19-
import { withDashboardProvider } from "testHelpers/storybook";
19+
import { withDashboardProvider, withProvisioners } from "testHelpers/storybook";
2020
import { TemplateVersionEditor } from "./TemplateVersionEditor";
2121

2222
const meta: Meta<typeof TemplateVersionEditor> = {
@@ -49,6 +49,101 @@ type Story = StoryObj<typeof TemplateVersionEditor>;
4949

5050
export const Example: Story = {};
5151

52+
export const UndefinedLogs: Story = {
53+
args: {
54+
defaultTab: "logs",
55+
buildLogs: undefined,
56+
templateVersion: {
57+
...MockTemplateVersion,
58+
job: MockRunningProvisionerJob,
59+
},
60+
},
61+
};
62+
63+
export const EmptyLogs: Story = {
64+
args: {
65+
defaultTab: "logs",
66+
buildLogs: [],
67+
templateVersion: {
68+
...MockTemplateVersion,
69+
job: MockRunningProvisionerJob,
70+
},
71+
},
72+
};
73+
74+
export const CouldntGetProvisioners: Story = {
75+
args: {
76+
defaultTab: "logs",
77+
buildLogs: [],
78+
templateVersion: {
79+
...MockTemplateVersion,
80+
job: MockRunningProvisionerJob,
81+
},
82+
},
83+
};
84+
85+
export const NoProvisioners: Story = {
86+
args: {
87+
defaultTab: "logs",
88+
buildLogs: [],
89+
templateVersion: {
90+
...MockTemplateVersion,
91+
job: MockRunningProvisionerJob,
92+
organization_id: "org-id",
93+
},
94+
},
95+
decorators: [withProvisioners],
96+
parameters: {
97+
organization_id: "org-id",
98+
tags: MockRunningProvisionerJob.tags,
99+
provisioners: [],
100+
}
101+
};
102+
103+
export const UnhealthyProvisioners: Story = {
104+
args: {
105+
defaultTab: "logs",
106+
buildLogs: [],
107+
templateVersion: {
108+
...MockTemplateVersion,
109+
job: MockRunningProvisionerJob,
110+
organization_id: "org-id"
111+
},
112+
},
113+
decorators: [withProvisioners],
114+
parameters: {
115+
organization_id: "org-id",
116+
tags: MockRunningProvisionerJob.tags,
117+
provisioners: [
118+
{
119+
last_seen_at: new Date(new Date().getTime() - 5 * 60 * 1000).toISOString()
120+
},
121+
],
122+
}
123+
};
124+
125+
export const HealthyProvisioners: Story = {
126+
args: {
127+
defaultTab: "logs",
128+
buildLogs: [],
129+
templateVersion: {
130+
...MockTemplateVersion,
131+
job: MockRunningProvisionerJob,
132+
organization_id: "org-id"
133+
},
134+
},
135+
decorators: [withProvisioners],
136+
parameters: {
137+
organization_id: "org-id",
138+
tags: MockRunningProvisionerJob.tags,
139+
provisioners: [
140+
{
141+
last_seen_at: new Date(),
142+
},
143+
],
144+
}
145+
};
146+
52147
export const Logs: Story = {
53148
args: {
54149
defaultTab: "logs",

0 commit comments

Comments
 (0)