Merge pull request #994 from benphelps/fix-970

Fix: improve swarm status for replicated services & prefer stats for local containers
pull/1008/head
shamoon 2 years ago committed by GitHub
commit a25606cfe9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,7 +12,7 @@ export default function Status({ service }) {
</div> </div>
} }
if (data && data.status === "running") { if (data && data.status.includes("running")) {
if (data.health === "starting") { if (data.health === "starting") {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.health}>
@ -36,7 +36,7 @@ export default function Status({ service }) {
); );
} }
if (data && (data.status === "not found" || data.status === "exited")) { if (data && (data.status === "not found" || data.status === "exited" || data.status?.startsWith("partial"))) {
return ( return (
<div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}> <div className="w-auto px-1.5 py-0.5 text-center bg-theme-500/10 dark:bg-theme-900/50 rounded-b-[3px] overflow-hidden" title={data.status}>
<div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.status}</div> <div className="text-[8px] font-bold text-orange-400/50 dark:text-orange-400/80 uppercase">{data.status}</div>

@ -53,17 +53,25 @@ export default async function handler(req, res) {
}) })
.catch(() => []); .catch(() => []);
// For now we are only interested in the first one (in case replicas > 1).
// TODO: Show the result for all replicas/containers? // TODO: Show the result for all replicas/containers?
const taskContainerId = tasks.at(0)?.Status?.ContainerStatus?.ContainerID; // We can only get stats for 'local' containers so try to find one
const localContainerIDs = containers.map(c => c.Id);
const task = tasks.find(t => localContainerIDs.includes(t.Status?.ContainerStatus?.ContainerID)) ?? tasks.at(0);
const taskContainerId = task?.Status?.ContainerStatus?.ContainerID;
if (taskContainerId) { if (taskContainerId) {
const container = docker.getContainer(taskContainerId); try {
const stats = await container.stats({ stream: false }); const container = docker.getContainer(taskContainerId);
const stats = await container.stats({ stream: false });
return res.status(200).json({ return res.status(200).json({
stats, stats,
}); });
} catch (e) {
return res.status(200).json({
error: "Unable to retrieve stats"
})
}
} }
} }

@ -44,32 +44,65 @@ export default async function handler(req, res) {
} }
if (dockerArgs.swarm) { if (dockerArgs.swarm) {
const tasks = await docker.listTasks({ const serviceInfo = await docker.getService(containerName).inspect()
.catch(() => undefined);
if (!serviceInfo) {
return res.status(404).send({
status: "not found",
});
}
const tasks = await docker
.listTasks({
filters: { filters: {
service: [containerName], service: [containerName],
// A service can have several offline containers, we only look for an active one.
"desired-state": ["running"], "desired-state": ["running"],
}, },
}) })
.catch(() => []); .catch(() => []);
// For now we are only interested in the first one (in case replicas > 1). if (serviceInfo.Spec.Mode?.Replicated) {
// TODO: Show the result for all replicas/containers? // Replicated service, check n replicas
const taskContainerId = tasks.at(0)?.Status?.ContainerStatus?.ContainerID; const replicas = parseInt(serviceInfo.Spec.Mode?.Replicated?.Replicas, 10);
if (tasks.length === replicas) {
if (taskContainerId) { return res.status(200).json({
const container = docker.getContainer(taskContainerId); status: `running ${tasks.length}/${replicas}`,
const info = await container.inspect(); });
}
return res.status(200).json({ if (tasks.length > 0) {
status: info.State.Status, return res.status(200).json({
health: info.State.Health?.Status, status: `partial ${tasks.length}/${replicas}`,
}); });
}
} else {
// Global service, prefer 'local' containers
const localContainerIDs = containers.map(c => c.Id);
const task = tasks.find(t => localContainerIDs.includes(t.Status?.ContainerStatus?.ContainerID)) ?? tasks.at(0);
const taskContainerId = task?.Status?.ContainerStatus?.ContainerID;
if (taskContainerId) {
try {
const container = docker.getContainer(taskContainerId);
const info = await container.inspect();
return res.status(200).json({
status: info.State.Status,
health: info.State.Health?.Status,
});
} catch (e) {
if (task) {
return res.status(200).json({
status: task.Status.State
})
}
}
}
} }
} }
return res.status(200).send({ return res.status(404).send({
error: "not found", status: "not found",
}); });
} catch (e) { } catch (e) {
logger.error(e); logger.error(e);

@ -22,7 +22,7 @@ export default function Component({ service }) {
return <Container error={finalError} />; return <Container error={finalError} />;
} }
if (statusData && statusData.status !== "running") { if (statusData && !(statusData.status.includes("running") || statusData.status.includes("partial"))) {
return ( return (
<Container> <Container>
<Block label={t("widget.status")} value={t("docker.offline")} /> <Block label={t("widget.status")} value={t("docker.offline")} />

Loading…
Cancel
Save