mirror of
https://github.com/amir20/dozzle.git
synced 2026-06-23 04:10:12 +00:00
feat: detect podman vs docker and show runtime icon (#4717)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vendored
+1
@@ -184,6 +184,7 @@ declare module 'vue' {
|
||||
SideDrawer: typeof import('./components/common/SideDrawer.vue')['default']
|
||||
SideMenu: typeof import('./components/SideMenu.vue')['default']
|
||||
SidePanel: typeof import('./components/SidePanel.vue')['default']
|
||||
'SimpleIcons:podman': typeof import('~icons/simple-icons/podman')['default']
|
||||
SimpleLogItem: typeof import('./components/LogViewer/SimpleLogItem.vue')['default']
|
||||
SkippedEntriesLogItem: typeof import('./components/LogViewer/SkippedEntriesLogItem.vue')['default']
|
||||
SlideTransition: typeof import('./components/common/SlideTransition.vue')['default']
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
<template>
|
||||
<div class="card bg-base-100">
|
||||
<div class="card-body flex gap-2 max-md:p-4">
|
||||
<div class="flex flex-row gap-2 overflow-hidden">
|
||||
<div class="flex items-center gap-1 truncate text-xl font-semibold">
|
||||
<HostIcon :type="host.type" class="flex-none" />
|
||||
<div class="truncate">
|
||||
{{ host.name }}
|
||||
</div>
|
||||
<div class="card-body flex gap-3 max-md:p-4">
|
||||
<div class="flex flex-row items-center gap-3 overflow-hidden">
|
||||
<div class="flex min-w-0 items-center gap-2 text-lg font-semibold tracking-tight md:text-xl">
|
||||
<HostIcon :type="host.type" class="text-base-content/80 flex-none" />
|
||||
<div class="truncate">{{ host.name }}</div>
|
||||
|
||||
<span class="badge badge-error badge-xs gap-2 p-2" v-if="!host.available">
|
||||
<span class="badge badge-error badge-xs gap-1 p-2 font-normal" v-if="!host.available">
|
||||
<carbon:warning />
|
||||
offline
|
||||
</span>
|
||||
<span
|
||||
class="badge badge-success badge-xs gap-2 p-2"
|
||||
class="badge badge-success badge-xs gap-1 p-2 font-normal"
|
||||
:class="{ 'badge-warning': config.version != host.agentVersion }"
|
||||
v-else-if="host.type == 'agent'"
|
||||
title="Dozzle Agent"
|
||||
@@ -21,12 +19,19 @@
|
||||
{{ host.agentVersion }}
|
||||
</span>
|
||||
</div>
|
||||
<ul class="ml-auto flex flex-row flex-wrap gap-x-2 text-sm max-md:text-xs md:gap-3">
|
||||
<li class="flex items-center gap-1">
|
||||
<octicon:container-24 class="inline-block" />
|
||||
|
||||
<ul
|
||||
class="text-base-content/60 ml-auto flex shrink-0 flex-row flex-wrap items-center gap-x-3 text-xs tabular-nums md:text-sm"
|
||||
>
|
||||
<li class="flex items-center gap-1.5">
|
||||
<octicon:container-24 class="size-3.5" />
|
||||
{{ $t("label.container", hostContainers.length) }}
|
||||
</li>
|
||||
<li class="flex items-center gap-1"><mdi:docker class="inline-block" /> {{ host.dockerVersion }}</li>
|
||||
<li class="flex items-center gap-1.5" :title="runtimeLabel">
|
||||
<simple-icons:podman v-if="host.runtime === 'podman'" class="size-3.5" />
|
||||
<mdi:docker v-else class="size-3.5" />
|
||||
{{ host.dockerVersion }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +40,7 @@
|
||||
:icon="PhCpu"
|
||||
:value="stats.weighted.movingAverage.totalCPU"
|
||||
:chartData="cpuHistory"
|
||||
container-class="border-primary/40 bg-primary/20"
|
||||
container-class="bg-primary/10"
|
||||
text-class="text-primary"
|
||||
bar-class="bg-primary"
|
||||
:formatValue="(value) => `${value.toFixed(1)}%`"
|
||||
@@ -46,7 +51,7 @@
|
||||
:icon="PhMemory"
|
||||
:value="stats.weighted.movingAverage.totalMemUsage"
|
||||
:chartData="memHistory"
|
||||
container-class="border-secondary/40 bg-secondary/20"
|
||||
container-class="bg-secondary/10"
|
||||
text-class="text-secondary"
|
||||
bar-class="bg-secondary"
|
||||
:formatValue="(value) => formatBytes(value, { decimals: 1 })"
|
||||
@@ -78,6 +83,8 @@ const hostContainers = computed(() =>
|
||||
containers.value.filter((container) => container.host === props.host.id && container.state === "running"),
|
||||
);
|
||||
|
||||
const runtimeLabel = computed(() => (props.host.runtime === "podman" ? "Podman" : "Docker"));
|
||||
|
||||
function toContainerCores(container: Container): number {
|
||||
if (container.cpuLimit && container.cpuLimit > 0) {
|
||||
return container.cpuLimit;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
>
|
||||
<template #value="{ hoveredValue }">
|
||||
<span class="tabular-nums">
|
||||
<span class="font-semibold"> {{ Math.max(0, hoveredValue ?? totalStat.cpu).toFixed(2) }}% </span>
|
||||
<span class="font-semibold"> {{ Math.max(0, hoveredValue ?? totalStat.cpu).toFixed(1) }}% </span>
|
||||
<span class="text-base-content/60 max-md:hidden"> / {{ roundCPU(limits.cpu) }} CPU</span>
|
||||
</span>
|
||||
</template>
|
||||
@@ -34,7 +34,9 @@
|
||||
>
|
||||
<template #value="{ hoveredValue }">
|
||||
<span class="tabular-nums">
|
||||
<span class="font-semibold">{{ formatBytes(hoveredValue ?? totalStat.memoryUsage) }}</span>
|
||||
<span class="font-semibold">{{
|
||||
formatBytes(hoveredValue ?? totalStat.memoryUsage, { short: true, decimals: 1 })
|
||||
}}</span>
|
||||
<span class="text-base-content/60 max-md:hidden">
|
||||
/ {{ formatBytes(limits.memory, { short: true, decimals: 1 }) }}</span
|
||||
>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="rounded-lg border p-2 md:p-3" :class="containerClass">
|
||||
<div class="rounded-lg p-2 md:p-3" :class="containerClass">
|
||||
<div class="mb-2 flex items-center gap-1.5 text-sm font-medium" :class="textClass">
|
||||
<component :is="icon" class="text-lg" />
|
||||
<span>{{ label }}</span>
|
||||
|
||||
@@ -7,6 +7,7 @@ export type Host = {
|
||||
endpoint: string;
|
||||
available: boolean;
|
||||
dockerVersion: string;
|
||||
runtime?: "docker" | "podman";
|
||||
agentVersion: string;
|
||||
group?: string;
|
||||
};
|
||||
|
||||
@@ -388,6 +388,7 @@ func (c *Client) Host(ctx context.Context) (container.Host, error) {
|
||||
Endpoint: c.endpoint,
|
||||
Type: "agent",
|
||||
DockerVersion: info.Host.DockerVersion,
|
||||
Runtime: info.Host.Runtime,
|
||||
AgentVersion: info.Host.AgentVersion,
|
||||
Group: c.group,
|
||||
}
|
||||
|
||||
@@ -937,6 +937,7 @@ type Host struct {
|
||||
Memory uint64 `protobuf:"varint,10,opt,name=memory,proto3" json:"memory,omitempty"`
|
||||
AgentVersion string `protobuf:"bytes,11,opt,name=agentVersion,proto3" json:"agentVersion,omitempty"`
|
||||
DockerVersion string `protobuf:"bytes,12,opt,name=dockerVersion,proto3" json:"dockerVersion,omitempty"`
|
||||
Runtime string `protobuf:"bytes,13,opt,name=runtime,proto3" json:"runtime,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -1055,6 +1056,13 @@ func (x *Host) GetDockerVersion() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Host) GetRuntime() string {
|
||||
if x != nil {
|
||||
return x.Runtime
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type NotificationSubscription struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
@@ -1471,7 +1479,7 @@ const file_types_proto_rawDesc = "" +
|
||||
"\tcontainer\x18\x06 \x01(\v2\x13.protobuf.ContainerR\tcontainer\x1aB\n" +
|
||||
"\x14ActorAttributesEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xaf\x03\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xc9\x03\n" +
|
||||
"\x04Host\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12 \n" +
|
||||
@@ -1485,7 +1493,8 @@ const file_types_proto_rawDesc = "" +
|
||||
"\x06memory\x18\n" +
|
||||
" \x01(\x04R\x06memory\x12\"\n" +
|
||||
"\fagentVersion\x18\v \x01(\tR\fagentVersion\x12$\n" +
|
||||
"\rdockerVersion\x18\f \x01(\tR\rdockerVersion\x1a9\n" +
|
||||
"\rdockerVersion\x18\f \x01(\tR\rdockerVersion\x12\x18\n" +
|
||||
"\aruntime\x18\r \x01(\tR\aruntime\x1a9\n" +
|
||||
"\vLabelsEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xea\x02\n" +
|
||||
|
||||
@@ -270,6 +270,7 @@ func (s *server) HostInfo(ctx context.Context, in *pb.HostInfoRequest) (*pb.Host
|
||||
CpuCores: uint32(host.NCPU),
|
||||
Memory: uint64(host.MemTotal),
|
||||
DockerVersion: host.DockerVersion,
|
||||
Runtime: host.Runtime,
|
||||
AgentVersion: s.version,
|
||||
},
|
||||
}, nil
|
||||
|
||||
@@ -22,6 +22,7 @@ type Host struct {
|
||||
MemTotal int64 `json:"memTotal"`
|
||||
Endpoint string `json:"endpoint"`
|
||||
DockerVersion string `json:"dockerVersion"`
|
||||
Runtime string `json:"runtime,omitempty"`
|
||||
AgentVersion string `json:"agentVersion,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Available bool `json:"available"`
|
||||
|
||||
@@ -37,6 +37,7 @@ type DockerCLI interface {
|
||||
ExecAttach(ctx context.Context, execID string, config client.ExecAttachOptions) (client.ExecAttachResult, error)
|
||||
ExecResize(ctx context.Context, execID string, options client.ExecResizeOptions) (client.ExecResizeResult, error)
|
||||
Info(ctx context.Context, options client.InfoOptions) (client.SystemInfoResult, error)
|
||||
ServerVersion(ctx context.Context, options client.ServerVersionOptions) (client.ServerVersionResult, error)
|
||||
ImagePull(ctx context.Context, refStr string, options client.ImagePullOptions) (client.ImagePullResponse, error)
|
||||
ContainerRemove(ctx context.Context, containerID string, options client.ContainerRemoveOptions) (client.ContainerRemoveResult, error)
|
||||
ContainerCreate(ctx context.Context, options client.ContainerCreateOptions) (client.ContainerCreateResult, error)
|
||||
@@ -66,6 +67,7 @@ func NewClient(cli DockerCLI, host container.Host) *DockerClient {
|
||||
host.NCPU = info.NCPU
|
||||
host.MemTotal = info.MemTotal
|
||||
host.DockerVersion = info.ServerVersion
|
||||
host.Runtime = detectRuntime(cli, info)
|
||||
host.Swarm = info.Swarm.NodeID != ""
|
||||
|
||||
return &DockerClient{
|
||||
@@ -139,6 +141,24 @@ func NewRemoteClient(host container.Host) (*DockerClient, error) {
|
||||
return NewClient(cli, host), nil
|
||||
}
|
||||
|
||||
func detectRuntime(cli DockerCLI, info system.Info) string {
|
||||
version, err := cli.ServerVersion(context.Background(), client.ServerVersionOptions{})
|
||||
if err == nil {
|
||||
for _, c := range version.Components {
|
||||
if strings.Contains(strings.ToLower(c.Name), "podman") {
|
||||
return "podman"
|
||||
}
|
||||
}
|
||||
if strings.Contains(strings.ToLower(version.Platform.Name), "podman") {
|
||||
return "podman"
|
||||
}
|
||||
}
|
||||
if strings.Contains(strings.ToLower(info.OperatingSystem), "podman") {
|
||||
return "podman"
|
||||
}
|
||||
return "docker"
|
||||
}
|
||||
|
||||
// Finds a container by id, skipping the filters
|
||||
func (d *DockerClient) FindContainer(ctx context.Context, id string) (container.Container, error) {
|
||||
log.Debug().Str("id", id).Msg("Finding container")
|
||||
|
||||
@@ -115,6 +115,7 @@ message Host {
|
||||
uint64 memory = 10;
|
||||
string agentVersion = 11;
|
||||
string dockerVersion = 12;
|
||||
string runtime = 13;
|
||||
}
|
||||
|
||||
enum ContainerAction {
|
||||
|
||||
Reference in New Issue
Block a user