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']
|
SideDrawer: typeof import('./components/common/SideDrawer.vue')['default']
|
||||||
SideMenu: typeof import('./components/SideMenu.vue')['default']
|
SideMenu: typeof import('./components/SideMenu.vue')['default']
|
||||||
SidePanel: typeof import('./components/SidePanel.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']
|
SimpleLogItem: typeof import('./components/LogViewer/SimpleLogItem.vue')['default']
|
||||||
SkippedEntriesLogItem: typeof import('./components/LogViewer/SkippedEntriesLogItem.vue')['default']
|
SkippedEntriesLogItem: typeof import('./components/LogViewer/SkippedEntriesLogItem.vue')['default']
|
||||||
SlideTransition: typeof import('./components/common/SlideTransition.vue')['default']
|
SlideTransition: typeof import('./components/common/SlideTransition.vue')['default']
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card bg-base-100">
|
<div class="card bg-base-100">
|
||||||
<div class="card-body flex gap-2 max-md:p-4">
|
<div class="card-body flex gap-3 max-md:p-4">
|
||||||
<div class="flex flex-row gap-2 overflow-hidden">
|
<div class="flex flex-row items-center gap-3 overflow-hidden">
|
||||||
<div class="flex items-center gap-1 truncate text-xl font-semibold">
|
<div class="flex min-w-0 items-center gap-2 text-lg font-semibold tracking-tight md:text-xl">
|
||||||
<HostIcon :type="host.type" class="flex-none" />
|
<HostIcon :type="host.type" class="text-base-content/80 flex-none" />
|
||||||
<div class="truncate">
|
<div class="truncate">{{ host.name }}</div>
|
||||||
{{ 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 />
|
<carbon:warning />
|
||||||
offline
|
offline
|
||||||
</span>
|
</span>
|
||||||
<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 }"
|
:class="{ 'badge-warning': config.version != host.agentVersion }"
|
||||||
v-else-if="host.type == 'agent'"
|
v-else-if="host.type == 'agent'"
|
||||||
title="Dozzle Agent"
|
title="Dozzle Agent"
|
||||||
@@ -21,12 +19,19 @@
|
|||||||
{{ host.agentVersion }}
|
{{ host.agentVersion }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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">
|
<ul
|
||||||
<octicon:container-24 class="inline-block" />
|
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) }}
|
{{ $t("label.container", hostContainers.length) }}
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -35,7 +40,7 @@
|
|||||||
:icon="PhCpu"
|
:icon="PhCpu"
|
||||||
:value="stats.weighted.movingAverage.totalCPU"
|
:value="stats.weighted.movingAverage.totalCPU"
|
||||||
:chartData="cpuHistory"
|
:chartData="cpuHistory"
|
||||||
container-class="border-primary/40 bg-primary/20"
|
container-class="bg-primary/10"
|
||||||
text-class="text-primary"
|
text-class="text-primary"
|
||||||
bar-class="bg-primary"
|
bar-class="bg-primary"
|
||||||
:formatValue="(value) => `${value.toFixed(1)}%`"
|
:formatValue="(value) => `${value.toFixed(1)}%`"
|
||||||
@@ -46,7 +51,7 @@
|
|||||||
:icon="PhMemory"
|
:icon="PhMemory"
|
||||||
:value="stats.weighted.movingAverage.totalMemUsage"
|
:value="stats.weighted.movingAverage.totalMemUsage"
|
||||||
:chartData="memHistory"
|
:chartData="memHistory"
|
||||||
container-class="border-secondary/40 bg-secondary/20"
|
container-class="bg-secondary/10"
|
||||||
text-class="text-secondary"
|
text-class="text-secondary"
|
||||||
bar-class="bg-secondary"
|
bar-class="bg-secondary"
|
||||||
:formatValue="(value) => formatBytes(value, { decimals: 1 })"
|
: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"),
|
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 {
|
function toContainerCores(container: Container): number {
|
||||||
if (container.cpuLimit && container.cpuLimit > 0) {
|
if (container.cpuLimit && container.cpuLimit > 0) {
|
||||||
return container.cpuLimit;
|
return container.cpuLimit;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
>
|
>
|
||||||
<template #value="{ hoveredValue }">
|
<template #value="{ hoveredValue }">
|
||||||
<span class="tabular-nums">
|
<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 class="text-base-content/60 max-md:hidden"> / {{ roundCPU(limits.cpu) }} CPU</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -34,7 +34,9 @@
|
|||||||
>
|
>
|
||||||
<template #value="{ hoveredValue }">
|
<template #value="{ hoveredValue }">
|
||||||
<span class="tabular-nums">
|
<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">
|
<span class="text-base-content/60 max-md:hidden">
|
||||||
/ {{ formatBytes(limits.memory, { short: true, decimals: 1 }) }}</span
|
/ {{ formatBytes(limits.memory, { short: true, decimals: 1 }) }}</span
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<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">
|
<div class="mb-2 flex items-center gap-1.5 text-sm font-medium" :class="textClass">
|
||||||
<component :is="icon" class="text-lg" />
|
<component :is="icon" class="text-lg" />
|
||||||
<span>{{ label }}</span>
|
<span>{{ label }}</span>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export type Host = {
|
|||||||
endpoint: string;
|
endpoint: string;
|
||||||
available: boolean;
|
available: boolean;
|
||||||
dockerVersion: string;
|
dockerVersion: string;
|
||||||
|
runtime?: "docker" | "podman";
|
||||||
agentVersion: string;
|
agentVersion: string;
|
||||||
group?: string;
|
group?: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -388,6 +388,7 @@ func (c *Client) Host(ctx context.Context) (container.Host, error) {
|
|||||||
Endpoint: c.endpoint,
|
Endpoint: c.endpoint,
|
||||||
Type: "agent",
|
Type: "agent",
|
||||||
DockerVersion: info.Host.DockerVersion,
|
DockerVersion: info.Host.DockerVersion,
|
||||||
|
Runtime: info.Host.Runtime,
|
||||||
AgentVersion: info.Host.AgentVersion,
|
AgentVersion: info.Host.AgentVersion,
|
||||||
Group: c.group,
|
Group: c.group,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -937,6 +937,7 @@ type Host struct {
|
|||||||
Memory uint64 `protobuf:"varint,10,opt,name=memory,proto3" json:"memory,omitempty"`
|
Memory uint64 `protobuf:"varint,10,opt,name=memory,proto3" json:"memory,omitempty"`
|
||||||
AgentVersion string `protobuf:"bytes,11,opt,name=agentVersion,proto3" json:"agentVersion,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"`
|
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
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@@ -1055,6 +1056,13 @@ func (x *Host) GetDockerVersion() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Host) GetRuntime() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Runtime
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
type NotificationSubscription struct {
|
type NotificationSubscription struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Id int32 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
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" +
|
"\tcontainer\x18\x06 \x01(\v2\x13.protobuf.ContainerR\tcontainer\x1aB\n" +
|
||||||
"\x14ActorAttributesEntry\x12\x10\n" +
|
"\x14ActorAttributesEntry\x12\x10\n" +
|
||||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\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" +
|
"\x04Host\x12\x0e\n" +
|
||||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
|
||||||
"\x04name\x18\x02 \x01(\tR\x04name\x12 \n" +
|
"\x04name\x18\x02 \x01(\tR\x04name\x12 \n" +
|
||||||
@@ -1485,7 +1493,8 @@ const file_types_proto_rawDesc = "" +
|
|||||||
"\x06memory\x18\n" +
|
"\x06memory\x18\n" +
|
||||||
" \x01(\x04R\x06memory\x12\"\n" +
|
" \x01(\x04R\x06memory\x12\"\n" +
|
||||||
"\fagentVersion\x18\v \x01(\tR\fagentVersion\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" +
|
"\vLabelsEntry\x12\x10\n" +
|
||||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xea\x02\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),
|
CpuCores: uint32(host.NCPU),
|
||||||
Memory: uint64(host.MemTotal),
|
Memory: uint64(host.MemTotal),
|
||||||
DockerVersion: host.DockerVersion,
|
DockerVersion: host.DockerVersion,
|
||||||
|
Runtime: host.Runtime,
|
||||||
AgentVersion: s.version,
|
AgentVersion: s.version,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type Host struct {
|
|||||||
MemTotal int64 `json:"memTotal"`
|
MemTotal int64 `json:"memTotal"`
|
||||||
Endpoint string `json:"endpoint"`
|
Endpoint string `json:"endpoint"`
|
||||||
DockerVersion string `json:"dockerVersion"`
|
DockerVersion string `json:"dockerVersion"`
|
||||||
|
Runtime string `json:"runtime,omitempty"`
|
||||||
AgentVersion string `json:"agentVersion,omitempty"`
|
AgentVersion string `json:"agentVersion,omitempty"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Available bool `json:"available"`
|
Available bool `json:"available"`
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ type DockerCLI interface {
|
|||||||
ExecAttach(ctx context.Context, execID string, config client.ExecAttachOptions) (client.ExecAttachResult, error)
|
ExecAttach(ctx context.Context, execID string, config client.ExecAttachOptions) (client.ExecAttachResult, error)
|
||||||
ExecResize(ctx context.Context, execID string, options client.ExecResizeOptions) (client.ExecResizeResult, error)
|
ExecResize(ctx context.Context, execID string, options client.ExecResizeOptions) (client.ExecResizeResult, error)
|
||||||
Info(ctx context.Context, options client.InfoOptions) (client.SystemInfoResult, 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)
|
ImagePull(ctx context.Context, refStr string, options client.ImagePullOptions) (client.ImagePullResponse, error)
|
||||||
ContainerRemove(ctx context.Context, containerID string, options client.ContainerRemoveOptions) (client.ContainerRemoveResult, error)
|
ContainerRemove(ctx context.Context, containerID string, options client.ContainerRemoveOptions) (client.ContainerRemoveResult, error)
|
||||||
ContainerCreate(ctx context.Context, options client.ContainerCreateOptions) (client.ContainerCreateResult, 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.NCPU = info.NCPU
|
||||||
host.MemTotal = info.MemTotal
|
host.MemTotal = info.MemTotal
|
||||||
host.DockerVersion = info.ServerVersion
|
host.DockerVersion = info.ServerVersion
|
||||||
|
host.Runtime = detectRuntime(cli, info)
|
||||||
host.Swarm = info.Swarm.NodeID != ""
|
host.Swarm = info.Swarm.NodeID != ""
|
||||||
|
|
||||||
return &DockerClient{
|
return &DockerClient{
|
||||||
@@ -139,6 +141,24 @@ func NewRemoteClient(host container.Host) (*DockerClient, error) {
|
|||||||
return NewClient(cli, host), nil
|
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
|
// Finds a container by id, skipping the filters
|
||||||
func (d *DockerClient) FindContainer(ctx context.Context, id string) (container.Container, error) {
|
func (d *DockerClient) FindContainer(ctx context.Context, id string) (container.Container, error) {
|
||||||
log.Debug().Str("id", id).Msg("Finding container")
|
log.Debug().Str("id", id).Msg("Finding container")
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ message Host {
|
|||||||
uint64 memory = 10;
|
uint64 memory = 10;
|
||||||
string agentVersion = 11;
|
string agentVersion = 11;
|
||||||
string dockerVersion = 12;
|
string dockerVersion = 12;
|
||||||
|
string runtime = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ContainerAction {
|
enum ContainerAction {
|
||||||
|
|||||||
Reference in New Issue
Block a user