Compare commits

...

59 Commits

Author SHA1 Message Date
Amir Raminfar 4dfc0e3e59 fixes static errors 2025-04-21 11:11:21 -07:00
Amir Raminfar 4ebd0c3624 removes br check inside static logic 2025-04-21 11:03:19 -07:00
Amir Raminfar 10baad1d4a adds gzip to sse 2025-04-21 09:50:14 -07:00
Amir Raminfar cceab9bd29 feat: enables brotli globally 2025-04-21 09:37:39 -07:00
renovate[bot] bea1876c7c fix(deps): update dependency @intlify/unplugin-vue-i18n to ^6.0.7 (#3822)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 02:34:50 +00:00
Amir Raminfar ae7eee9bca chore: release v8.12.10
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-20 08:02:41 -07:00
Amir Raminfar d98b84e24a fix: fixes sql analytics when error occurs (#3820)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-19 16:44:40 +00:00
Amir Raminfar 18c87256cc fix: fixes alerts on mobile (#3819) 2025-04-19 09:41:57 -07:00
Amir Raminfar e96631930e chore: adds some shadows and makes colors better (#3818)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-19 08:04:59 -07:00
Amir Raminfar 76b1229341 chore: release v8.12.9
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-18 14:24:57 -07:00
renovate[bot] 440f9394d6 fix(deps): update all non-major dependencies (#3817)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-18 20:58:05 +00:00
Amir Raminfar ec792318e6 feat: adds better disabled colors and loader while fetching big logs (#3816) 2025-04-18 20:52:53 +00:00
Amir Raminfar 16db90b660 docs: updates docs to Ed25519
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-17 17:21:33 -07:00
Amir Raminfar eb22752b9a chore: updates to Ed25519 2025-04-17 17:20:19 -07:00
Amir Raminfar 642ab45ef7 chore: fixes tests
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-17 14:24:34 -07:00
renovate[bot] 12fadb9348 fix(deps): update all non-major dependencies (#3813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-17 14:09:33 -07:00
Amir Raminfar 1cf178e37d feat: more improvements to analytic and gzips logs for better performance (#3814) 2025-04-17 14:09:06 -07:00
Amir Raminfar 061cd0c445 feat: creates betters messaging for analytics mode (#3812) 2025-04-17 17:32:20 +00:00
renovate[bot] e8f796a7d6 fix(deps): update all non-major dependencies (#3811)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-17 15:42:02 +00:00
Amir Raminfar 78f94f1f16 chore: updates d.ts
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
2025-04-15 15:16:35 -07:00
renovate[bot] cc980361fd fix(deps): update module github.com/yuin/goldmark to v1.7.10 (#3809)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 18:55:20 +00:00
Amir Raminfar 736ad8ed5b chore: updates modules (#3808) 2025-04-15 11:28:30 -07:00
renovate[bot] d0dbd2051e fix(deps): update all non-major dependencies (#3807)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 15:54:30 +00:00
Amir Raminfar 40a17b4088 chore: release v8.12.8
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-14 08:33:33 -07:00
renovate[bot] b3da3d70a9 chore(deps): update dependency jsdom to ^26.1.0 (#3806)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-14 03:44:40 +00:00
Amir Raminfar 28588fdfd2 chore: fixes center css (#3804) 2025-04-13 15:31:42 -07:00
Amir Raminfar a33f7bf3b2 fix: reverts confirm password 2025-04-13 15:31:28 -07:00
Amir Raminfar febdbff0de fix(docs): updates typos in docs 2025-04-13 15:27:36 -07:00
Amir Raminfar 0fee11e036 fix: fixes broken link on container title (#3803)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-13 12:54:20 -07:00
Amir Raminfar b768cbfc89 docs: updates generate command 2025-04-13 12:33:10 -07:00
Amir Raminfar d43de49b6d fix: fixes collapse color visually hard to see on light theme (#3801) 2025-04-13 09:42:49 -07:00
Amir Raminfar facc137a93 chore: updates duckdb (#3799)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-12 21:05:28 +00:00
renovate[bot] a052f55dc6 fix(deps): update all non-major dependencies (#3798)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-12 21:00:54 +00:00
Amir Raminfar 481f2bd592 chore: format 2025-04-12 13:44:40 -07:00
Amir Raminfar b33ae4fa4e fix: Use /tmp instead of ./ to ensure that user permissions can be mounted correctly. (#3797) 2025-04-12 13:44:21 -07:00
Amir Raminfar f35c472088 chore: release v8.12.7
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
2025-04-11 09:42:13 -07:00
Amir Raminfar 7455a4c53c feat: improves generate with confirm to catch typos (#3794) 2025-04-11 09:16:04 -07:00
renovate[bot] 84101620f8 fix(deps): update dependency vite to v6.2.6 [security] (#3792)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 15:53:32 +00:00
renovate[bot] 51695b486e fix(deps): update dependency daisyui to v5.0.18 (#3793)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 15:53:16 +00:00
Piyush Dixit 2f84190faa feat: Add support for both .yml and .yaml files and prioritize .yml for users file (#3789)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-10 21:46:03 -07:00
Amir Raminfar ebcedb2a67 chore: cleans up proto tranformation (#3791)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-10 16:31:23 -07:00
Amir Raminfar a514168e45 chore: adds fully loaded to agent proto (#3787)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-09 17:33:44 -07:00
Amir Raminfar 6bb3777a64 chore: release v8.12.6 2025-04-09 15:18:37 -07:00
Amir Raminfar d22e6f9014 chore: removes unused imports 2025-04-09 15:17:42 -07:00
renovate[bot] b779998476 fix(deps): update all non-major dependencies (#3786)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-09 22:07:32 +00:00
Amir Raminfar 70c23b0b1e fix: fixes broken cpu and memory limits on swarm mode. correctly implements limits with agents (#3785) 2025-04-09 15:02:38 -07:00
Amir Raminfar ddff265023 fix: fixes cpu limit being miscalculated (#3782)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-09 08:58:21 -07:00
Amir Raminfar 52edcce8d8 chore: updates documentation
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-08 11:00:34 -07:00
Amir Raminfar 0f75010b35 chore: release v8.12.5 2025-04-08 10:51:06 -07:00
Amir Raminfar 5e228756f3 chore: fixes alpha on background 2025-04-08 10:50:43 -07:00
Amir Raminfar 3775170457 fix: fixes backdrop on fuzzy search (#3776) 2025-04-08 10:49:12 -07:00
renovate[bot] 42edc4c623 fix(deps): update all non-major dependencies (#3773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-08 16:04:46 +00:00
Amir Raminfar f363b6f366 feat: adds limit to docker containers (#3766) 2025-04-08 15:57:33 +00:00
Amir Raminfar df7e461876 chore: improves logging for duplicate hosts (#3772) 2025-04-08 08:50:02 -07:00
Andrea Titolo f691a22d05 fix: update and improve it locale (#3771) 2025-04-08 07:43:32 -07:00
Amir Raminfar 9c2e03727b fix: fixes mobile menu having the wrong padding (#3765)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
2025-04-07 23:57:50 +00:00
renovate[bot] 2177320259 fix(deps): update all non-major dependencies (#3763)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-07 03:37:35 +00:00
Agneev Mukherjee 2a2f6bc9c6 fix: use light mode bg color as theme color (#3757)
Push container / Push branches and PRs (push) Has been cancelled
Deploy VitePress site to Pages / build (push) Has been cancelled
Test / Typecheck (push) Has been cancelled
Test / JavaScript Tests (push) Has been cancelled
Test / Go Tests (push) Has been cancelled
Test / Go Staticcheck (push) Has been cancelled
Test / Integration Tests (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
2025-04-05 09:29:17 -07:00
renovate[bot] e4fab590b9 fix(deps): update all non-major dependencies (#3759)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-05 14:42:59 +00:00
76 changed files with 2111 additions and 1911 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ pre_cmd = []
rerun = false
rerun_delay = 500
send_interrupt = true
stop_on_error = false
stop_on_error = true
[color]
app = ""
+8 -7
View File
@@ -48,17 +48,18 @@ body:
id: environment
attributes:
label: 💻 Environment
description: Run `docker system info` and paste the output in the field below..
description: Run `docker system info` and paste the output in the field below.
validations:
required: true
- type: textarea
attributes:
label: 📜 Dozzle logs are required for debugging purposes. You may need to enable debug mode. See https://dozzle.dev/guide/debugging.
description: Drag log files or paste the logs into the text input below
validations:
required: true
- type: textarea
attributes:
label: 📸 If applicable, add screenshots to help explain your bug
description: Drag issues into the text input below
validations:
required: false
- type: textarea
attributes:
label: 📜 If applicable, attach your Dozzle logs. You many need to enable debug mode. See https://dozzle.dev/guide/debugging.
description: Drag screenshots into the text input below
validations:
required: false
+1
View File
@@ -61,6 +61,7 @@ RUN mkdir /data
FROM scratch
COPY --from=builder /data /data
COPY --from=builder /tmp /tmp
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /dozzle/dozzle /dozzle
+1 -1
View File
@@ -43,7 +43,7 @@ int:
docker compose up --build --force-recreate --exit-code-from playwright
shared_key.pem:
@openssl genpkey -algorithm RSA -out shared_key.pem -pkeyopt rsa_keygen_bits:2048
@openssl genpkey -algorithm Ed25519 -out shared_key.pem
shared_cert.pem: shared_key.pem
@openssl req -new -key shared_key.pem -out shared_request.csr -subj "/C=US/ST=California/L=San Francisco/O=Dozzle"
+1 -1
View File
@@ -15,7 +15,7 @@ watchEffect(() => {
if (theme === "auto") {
theme = mode.value;
}
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", theme == "dark" ? "#121212" : "#3FA68F");
document.querySelector('meta[name="theme-color"]')?.setAttribute("content", theme == "dark" ? "#121212" : "#F5F5F5");
document.documentElement.setAttribute("data-theme", theme);
});
</script>
+1 -1
View File
@@ -373,7 +373,7 @@ declare global {
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
// @ts-ignore
export type { DrawerWidth } from './composable/drawer'
@@ -6,15 +6,15 @@
<carbon:star class="swap-off" />
</label>
<div class="inline-flex items-center text-sm">
<div class="breadcrumbs p-0">
<div class="breadcrumbs p-0 font-mono">
<ul>
<li v-if="config.hosts.length > 1" class="font-thin max-md:hidden">
{{ container.hostLabel }}
</li>
<li>
<div v-if="otherContainers.length === 0" class="font-mono">{{ container.name }}</div>
<template v-if="otherContainers.length === 0">{{ container.name }}</template>
<div class="wrapper" ref="wrapper" v-else>
<button popovertarget="popover-container-list" class="btn btn-xs md:btn-sm anchor font-mono">
<button popovertarget="popover-container-list" class="btn btn-xs md:btn-sm anchor">
{{ container.name }} <carbon:caret-down />
</button>
@@ -25,8 +25,8 @@
class="status data-[state=exited]:status-error data-[state=running]:status-success"
:data-state="other.state"
></div>
<div class="font-mono" v-if="other.isSwarm">{{ other.swarmId }}</div>
<div class="font-mono" v-else>{{ other.name }}</div>
<div v-if="other.isSwarm">{{ other.swarmId }}</div>
<div v-else>{{ other.name }}</div>
<div v-if="other.state === 'running'">running</div>
<DistanceTime :date="other.created" strict class="text-base-content/70 text-xs" v-else />
</router-link>
@@ -42,6 +42,8 @@ function createFuzzySearchModal() {
"host",
{},
"running",
0,
0,
[],
),
new Container(
@@ -55,6 +57,8 @@ function createFuzzySearchModal() {
"host",
{},
"running",
0,
0,
[],
),
new Container(
@@ -68,6 +72,8 @@ function createFuzzySearchModal() {
"host",
{},
"running",
0,
0,
[],
),
],
+1 -1
View File
@@ -1,5 +1,5 @@
<template>
<div class="dropdown dropdown-open w-full">
<div class="dropdown dropdown-open w-full shadow-md">
<div class="input input-xl input-primary flex w-full items-center">
<mdi:magnify class="flex size-8" />
<input
@@ -2,7 +2,7 @@
<ScrollableView :scrollable="scrollable" v-if="group.containers.length && ready">
<template #header>
<div class="mx-2 flex items-center gap-2 md:ml-4">
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
<div class="@container flex flex-1 items-center gap-1.5 truncate md:gap-2">
<div class="inline-flex font-mono text-sm">
<div class="font-semibold">{{ $t("label.container", group.containers.length) }}</div>
</div>
+1 -1
View File
@@ -51,7 +51,7 @@
:style="`--value: ${Math.floor((weightedStats[host.id].weighted.totalMem / host.memTotal) * 100)};`"
role="progressbar"
>
{{ formatBytes(weightedStats[host.id].weighted.totalMem, 1) }}
{{ formatBytes(weightedStats[host.id].weighted.totalMem, { decimals: 1, short: true }) }}
</div>
</div>
</div>
@@ -105,6 +105,8 @@ describe("<ContainerEventSource />", () => {
"localhost",
{},
"created",
0,
0,
[],
),
},
+59 -23
View File
@@ -11,18 +11,26 @@
<textarea
v-model="query"
class="textarea textarea-primary w-full font-mono text-lg"
:class="{ 'textarea-error': error }"
:class="{ 'textarea-error!': error }"
:disabled="state === 'downloading'"
></textarea>
<div class="label max-h-48 overflow-y-auto pr-2">
<span class="label-text-alt text-error" v-if="error">{{ error }}</span>
<span class="label-text-alt" v-else>
Total {{ results.numRows }} records
<template v-if="results.numRows > pageLimit"> . Showing first {{ page.numRows }}. </template>
<div class="mt-2">
<span class="text-error" v-if="error">{{ error }}</span>
<span v-else-if="state === 'initializing'">{{ $t("analytics.creating_table") }}</span>
<span v-else-if="state === 'downloading'">{{
$t("analytics.downloading", { size: formatBytes(bytes, { decimals: 1 }) })
}}</span>
<span v-else-if="evaluating">{{ $t("analytics.evaluating_query") }}</span>
<span v-else>
{{ $t("analytics.total_records", { count: results.numRows.toLocaleString() }) }}
<template v-if="results.numRows > pageLimit">{{
$t("analytics.showing_first", { count: page.numRows.toLocaleString() })
}}</template>
</span>
</div>
</label>
</section>
<SQLTable :table="page" :loading="evaluating || !isReady" />
<SQLTable :table="page" :loading="evaluating || state !== 'ready'" />
</div>
</aside>
</template>
@@ -30,12 +38,15 @@
<script setup lang="ts">
import { Container } from "@/models/Container";
import { type Table } from "@apache-arrow/esnext-esm";
const { container } = defineProps<{ container: Container }>();
const query = ref("SELECT * FROM logs LIMIT 100");
const error = ref<string | null>(null);
const debouncedQuery = debouncedRef(query, 500);
const evaluating = ref(false);
const pageLimit = 1000;
const state = ref<"downloading" | "ready" | "initializing">("downloading");
const bytes = ref(0);
const url = withBase(
`/api/hosts/${container.host}/containers/${container.id}/logs?stdout=1&stderr=1&everything&jsonOnly`,
@@ -51,27 +62,49 @@ if (!response.ok) {
const { db, conn } = await useDuckDB();
const empty = await conn.query<Record<string, any>>(`SELECT 1 LIMIT 0`);
const { isReady } = useAsyncState(
async () => {
await db.registerFileBuffer("logs.json", new Uint8Array(await response.arrayBuffer()));
onMounted(async () => {
try {
state.value = "downloading";
const reader = response.body?.getReader();
if (!reader) throw new Error("No reader available from stream");
const chunks: Uint8Array[] = [];
bytes.value = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
bytes.value += value.length;
}
const arrayBuffer = new Uint8Array(bytes.value);
let position = 0;
for (const chunk of chunks) {
arrayBuffer.set(chunk, position);
position += chunk.length;
}
await db.registerFileBuffer("logs.json", arrayBuffer);
state.value = "initializing";
await conn.query(
`CREATE TABLE logs AS SELECT unnest(m) FROM read_json('logs.json', ignore_errors = true, format = 'newline_delimited')`,
);
},
undefined,
{
onError: (e) => {
console.error(e);
if (e instanceof Error) {
error.value = e.message;
}
},
},
);
state.value = "ready";
} catch (e) {
console.error(e);
if (e instanceof Error) {
error.value = e.message;
}
}
});
const results = computedAsync(
async () => {
if (isReady.value) {
if (state.value === "ready") {
return await conn.query<Record<string, any>>(debouncedQuery.value);
} else {
return empty;
@@ -89,7 +122,10 @@ const results = computedAsync(
},
);
whenever(evaluating, () => (error.value = null));
whenever(evaluating, () => {
error.value = null;
state.value = "ready";
});
const page = computed(() =>
results.value.numRows > pageLimit ? results.value.slice(0, pageLimit) : results.value,
) as unknown as ComputedRef<Table<Record<string, any>>>;
@@ -1,7 +1,17 @@
<template>
<div class="flex gap-4">
<StatMonitor :data="memoryData" label="mem" :stat-value="formatBytes(totalStat.memoryUsage)" />
<StatMonitor :data="cpuData" label="load" :stat-value="Math.max(0, totalStat.cpu).toFixed(2) + '%'" />
<StatMonitor
:data="memoryData"
label="mem"
:stat-value="formatBytes(totalStat.memoryUsage)"
:limit="formatBytes(limits.memory, { short: true, decimals: 1 })"
/>
<StatMonitor
:data="cpuData"
label="load"
:stat-value="Math.max(0, totalStat.cpu).toFixed(2) + '%'"
:limit="roundCPU(limits.cpu) + ' CPU'"
/>
</div>
</template>
@@ -15,6 +25,9 @@ const { containers } = defineProps<{
const totalStat = ref<Stat>({ cpu: 0, memory: 0, memoryUsage: 0 });
const { history, reset } = useSimpleRefHistory(totalStat, { capacity: 300 });
const { hosts } = useHosts();
const roundCPU = (num: number) => (Number.isInteger(num) ? num.toFixed(0) : num.toFixed(1));
watch(
() => containers,
@@ -42,6 +55,16 @@ watch(
{ immediate: true },
);
const limits = computed(() =>
containers.reduce(
(acc, c) => ({
cpu: acc.cpu + (c.cpuLimit > 0 ? c.cpuLimit : hosts.value[c.host].nCPU),
memory: acc.memory + (c.memoryLimit > 0 ? c.memoryLimit : hosts.value[c.host].memTotal),
}),
{ cpu: 0, memory: 0 },
),
);
useIntervalFn(() => {
totalStat.value = containers.reduce(
(acc, { stat }) => {
+16 -10
View File
@@ -1,25 +1,31 @@
<template>
<div class="hover:text-secondary relative" @mouseenter="mouseOver = true" @mouseleave="mouseOver = false">
<div class="border-primary hidden overflow-hidden rounded-xs border px-px pt-1 pb-px md:flex">
<div class="border-primary overflow-hidden rounded-xs border px-px pt-1 pb-px max-md:hidden">
<StatSparkline :data="data" @selected-point="onSelectedPoint" />
</div>
<div class="bg-base-200 inline-flex gap-1 rounded-sm p-px text-xs md:absolute md:-top-2 md:-left-0.5">
<div class="font-light uppercase">{{ label }}</div>
<div class="font-bold select-none">
{{ mouseOver ? (selectedPoint?.value ?? selectedPoint?.y ?? statValue) : statValue }}
<span v-if="limit !== -1 && !mouseOver" class="max-md:hidden"> / {{ limit }} </span>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
const { data, label, statValue } = defineProps<{ data: Point<unknown>[]; label: string; statValue: string | number }>();
let selectedPoint: Point<unknown> | undefined = $ref();
function onSelectedPoint(point: Point<unknown>) {
selectedPoint = point;
}
let mouseOver = $ref(false);
const {
data,
label,
statValue,
limit = -1,
} = defineProps<{
data: Point<unknown>[];
label: string;
statValue: string | number;
limit?: string | number;
}>();
const selectedPoint = ref<Point<unknown> | undefined>();
const onSelectedPoint = (point: Point<unknown>) => (selectedPoint.value = point);
const mouseOver = ref(false);
</script>
@@ -11,7 +11,7 @@ import { scaleLinear } from "d3-scale";
import { area, curveStep } from "d3-shape";
const d3 = { extent, scaleLinear, area, curveStep };
const { data, width = 150, height = 30 } = defineProps<{ data: Point<unknown>[]; width?: number; height?: number }>();
const { data, width = 175, height = 30 } = defineProps<{ data: Point<unknown>[]; width?: number; height?: number }>();
const x = d3.scaleLinear().range([0, width]);
const y = d3.scaleLinear().range([height, 0]);
@@ -2,7 +2,7 @@
<ScrollableView :scrollable="scrollable" v-if="containers.length && ready">
<template #header>
<div class="mx-2 flex items-center gap-2 md:ml-4">
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
<div class="@container flex flex-1 items-center gap-1.5 truncate md:gap-2">
<octicon:container-24 />
<div class="inline-flex font-mono text-sm">
<div class="font-semibold">{{ containers.length }} containers</div>
@@ -2,7 +2,7 @@
<ScrollableView :scrollable="scrollable" v-if="service.name">
<template #header>
<div class="mx-2 flex items-center gap-2 md:ml-4">
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
<div class="@container flex flex-1 items-center gap-1.5 truncate md:gap-2">
<ph:stack-simple />
<div class="inline-flex font-mono text-sm">
<div class="font-semibold">{{ service.name }}</div>
+1 -1
View File
@@ -2,7 +2,7 @@
<ScrollableView :scrollable="scrollable" v-if="stack.name">
<template #header>
<div class="mx-2 flex items-center gap-2 md:ml-4">
<div class="@container flex flex-1 gap-1.5 truncate md:gap-2">
<div class="@container flex flex-1 items-center gap-1.5 truncate md:gap-2">
<ph:stack />
<div class="inline-flex font-mono text-sm">
<div class="font-semibold">{{ stack.name }}</div>
+2 -2
View File
@@ -1,7 +1,7 @@
<template>
<div class="toast toast-end whitespace-normal max-md:m-0 max-md:w-full">
<div class="toast toast-end whitespace-normal max-md:end-auto max-md:m-0 max-md:max-w-full">
<div
class="alert max-w-xl max-md:rounded-none"
class="alert max-w-xl shadow-sm max-md:rounded-none"
v-for="{ toast, options: { timed } } in toasts"
:key="toast.id"
:class="{
+2 -6
View File
@@ -25,7 +25,7 @@
</Pane>
</Splitpanes>
<label
class="btn btn-circle swap bg-base-100 swap-rotate fixed bottom-4 -left-12 w-16 transition-all hover:-left-4"
class="btn btn-circle swap bg-base-content/10 swap-rotate border-base-content/20 hover:border-primary fixed bottom-4 -left-12 w-16 shadow-sm transition-all hover:-left-4"
:class="{ '-left-6!': collapseNav }"
v-if="!isMobile && !forceMenuHidden"
>
@@ -34,11 +34,7 @@
<mdi:chevron-left class="swap-off" />
</label>
</div>
<dialog
ref="modal"
class="modal items-start bg-white/20 transition-none backdrop:backdrop-blur-xs"
@close="open = false"
>
<dialog ref="modal" class="modal bg-base-300/50! items-start backdrop-blur-md transition-none!" @close="open = false">
<div class="modal-box max-w-2xl bg-transparent pt-20 shadow-none">
<FuzzySearchModal @close="open = false" v-if="open" />
</div>
-4
View File
@@ -127,10 +127,6 @@
}
}
nav {
padding-top: env(safe-area-inset-top);
}
body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
+2
View File
@@ -38,6 +38,8 @@ export class Container {
public readonly host: string,
public readonly labels = {} as Record<string, string>,
public state: ContainerState,
public readonly cpuLimit: number,
public readonly memoryLimit: number,
stats: Stat[],
public readonly group?: string,
public health?: ContainerHealth,
+2
View File
@@ -154,6 +154,8 @@ export const useContainerStore = defineStore("container", () => {
c.host,
c.labels,
c.state,
c.cpuLimit,
c.memoryLimit,
c.stats,
c.group,
c.health,
+2
View File
@@ -16,6 +16,8 @@ export type ContainerJson = {
readonly status: string;
readonly state: ContainerState;
readonly host: string;
readonly cpuLimit: number;
readonly memoryLimit: number;
readonly labels: Record<string, string>;
readonly stats: ContainerStat[];
readonly health?: ContainerHealth;
+11 -2
View File
@@ -1,10 +1,19 @@
export function formatBytes(bytes: number, decimals = 2) {
export function formatBytes(
bytes: number,
{ decimals = 2, short = false }: { decimals?: number; short?: boolean } = { decimals: 2, short: false },
) {
if (bytes === 0) return "0 Bytes";
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
const value = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
if (short) {
return value + sizes[i].charAt(0);
} else {
return value + " " + sizes[i];
}
}
export function getDeep(obj: Record<string, any>, path: string[]) {
+1 -1
View File
@@ -95,7 +95,7 @@ services:
playwright:
container_name: playwright
image: mcr.microsoft.com/playwright:v1.51.1-jammy
image: mcr.microsoft.com/playwright:v1.52.0-jammy
working_dir: /app
volumes:
- .:/app
+18 -7
View File
@@ -64,10 +64,21 @@ Note that when connecting remotely, you don't need to mount local Docker socket.
> [!TIP]
> You can connect to multiple agents by providing multiple `DOZZLE_REMOTE_AGENT` environment variables. For example, `DOZZLE_REMOTE_AGENT=agent1:7007,agent2:7007`.
> [!WARNING]
> Dozzle uses the Docker API to gather information about hosts. Each agent needs a unique host ID. They use Docker's system ID or node ID to identify the host. If you are using swarm, then the node ID is used. If you don't see all hosts, then you may have duplicate hosts configured that have the same host ID. To fix this, remove `/var/lib/docker/engine-id` file. See [FAQ](/guide/faq#i-am-seeing-duplicate-hosts-error-in-the-logs-how-do-i-fix-it) for more information.
## Common Issues
## Setting Up Healthcheck
### Agent Not Showing Up
If you are seeing `An agent with an existing ID was found. Removing the duplicate host.` then you have two hosts that use the same Server ID.
Dozzle utilizes the Docker API to collect information about hosts. Each agent requires a unique host ID that remains consistent across restarts to ensure proper identification. Currently, agents identify the host using either Docker's system ID or node ID.
If you are operating in a Swarm environment, the node ID will be employed for this purpose. However, if you notice that not all hosts are visible, it may be due to the presence of duplicate hosts configured with the same host ID.
To resolve this issue, you should remove `/var/lib/docker/engine-id` from your system and restart. This action will help eliminate any conflicts caused by duplicate host IDs. For additional information and troubleshooting tips, please refer to the [FAQ](/guide/faq#i-am-seeing-duplicate-hosts-error-in-the-logs-how-do-i-fix-it).
## Advanced Options
### Setting Up Healthcheck
You can set a healthcheck for the agent, similar to the healthcheck for the main Dozzle instance. When running in agent mode, healthcheck checks agent connection to Docker. If Docker is not reachable, the agent will be marked as unhealthy and will not be shown in the UI.
@@ -90,7 +101,7 @@ services:
- 7007:7007
```
## Changing Agent's Name
### Changing Agent's Name
Similar to Dozzle instance, you can change the agent's name by providing the `DOZZLE_HOSTNAME` environment variable. Here is an example:
@@ -117,7 +128,7 @@ services:
This will change the agent's name to `my-special-name` and will be reflected on the UI when connecting to the agent.
## Setting Up Filters
### Setting Up Filters
You can set up filters for the agent to limit the containers it can access. These filters are passed directly to Docker, restricting what Dozzle can view.
@@ -134,7 +145,7 @@ services:
This will restrict the agent to displaying only containers with the label `color`. Keep in mind that these filters are combined with the UI filters to narrow down the containers. To learn more about the different types of filters, read the [filters documentation](/guide/filters#ui-agents-and-user-filters).
## Custom Certificates
### Custom Certificates
By default, Dozzle uses self-signed certificates for communication between agents. This is a private certificate which is only valid to other Dozzle instances. This is secure and recommended for most use cases. However, if Dozzle is exposed externally and an attacker knows exactly which port the agent is running on, then they can set up their own Dozzle instance and connect to the agent. To prevent this, you can provide your own certificates.
@@ -169,7 +180,7 @@ This will mount the `cert.pem` and `key.pem` files to the agent. The agent will
To generate certificates, you can use the following command:
```sh
$ openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
$ openssl genpkey -algorithm Ed25519 -out key.pem
$ openssl req -new -key key.pem -out request.csr -subj "/C=US/ST=California/L=San Francisco/O=My Company"
$ openssl x509 -req -in request.csr -signkey key.pem -out cert.pem -days 365
```
+10 -5
View File
@@ -10,7 +10,12 @@ If you do not have an authentication solution, then Dozzle has a simple file-bas
## File-Based User Management
Dozzle supports multi-user authentication by setting `--auth-provider` to `simple`. In this mode, Dozzle will try to read `/data/users.yml`.
Dozzle supports multi-user authentication by setting `--auth-provider` to `simple`. In this mode, Dozzle will attempt to read the users file from `/data/`, prioritizing `users.yml` over `users.yaml` if both files are present. If only one of the files exists, it will be used. The log will indicate which file is being read (e.g., `Reading users.yml file`).
### Example file paths:
- `/data/users.yml`
- `/data/users.yaml`
The content of the file looks like:
@@ -20,7 +25,7 @@ users:
admin:
email: me@email.net
name: Admin
# Generate with docker run amir20/dozzle generate --name Admin --email me@email.net --password secret admin
# Generate with docker run run -it --rm amir20/dozzle generate --name Admin --email me@email.net --password secret admin
password: $2a$11$9ho4vY2LdJ/WBopFcsAS0uORC0x2vuFHQgT/yBqZyzclhHsoaIkzK
filter:
```
@@ -28,7 +33,7 @@ users:
Dozzle uses `email` to generate avatars using [Gravatar](https://gravatar.com/). It is optional. The password is hashed using `bcrypt` which can be generated using `docker run amir20/dozzle generate`.
> [!WARNING]
> In previous versions of Dozzle, SHA-256 was used to hash passwords. Bcrypt is now more secure and is recommended for future use. Dozzle will revert to SHA-256 if it does not find a bcrypt hash. It is advisable to update the password hash to bcrypt using `docker run amir20/dozzle generate`. For more details, see [this issue](https://github.com/amir20/dozzle/security/advisories/GHSA-w7qr-q9fh-fj35).
> In previous versions of Dozzle, SHA-256 was used to hash passwords. Bcrypt is now more secure and is recommended for future use. Dozzle will revert to SHA-256 if it does not find a bcrypt hash. It is advisable to update the password hash to bcrypt using `generate`. For more details, see [this issue](https://github.com/amir20/dozzle/security/advisories/GHSA-w7qr-q9fh-fj35).
You will need to mount this file for Dozzle to find it. Here is an example:
@@ -139,10 +144,10 @@ In this example, the `admin` user has no filter, so they can see all containers.
Dozzle has a built-in `generate` command to generate `users.yml`. Here is an example:
```sh
docker run amir20/dozzle generate admin --password password --email test@email.net --name "John Doe" --user-filter name=foo > users.yml
docker run -it --rm amir20/dozzle generate admin --password password --email test@email.net --name "John Doe" --user-filter name=foo > users.yml
```
In this example, `admin` is the username. Email and name are optional but recommended to display accurate avatars. `docker run amir20/dozzle generate --help` displays all options. The `--user-filter` flag is a comma-separated list of filters.
In this example, `admin` is the username. Email and name are optional but recommended to display accurate avatars. `docker run -it --rm amir20/dozzle generate --help` displays all options. The `--user-filter` flag is a comma-separated list of filters.
## Forward Proxy
+1 -1
View File
@@ -34,7 +34,7 @@ Configurations can be done with flags or environment variables. The table below
Dozzle supports generating `users.yml` file. This file is used to authenticate users. Here is an example:
```sh
docker run amir20/dozzle generate admin --password password --email test@email.net --name "John Doe" > users.yml
docker run -it --rm amir20/dozzle generate admin --password password --email test@email.net --name "John Doe" > users.yml
```
In this example, `admin` is the username. Email and name are optional but recommended to display accurate avatars. `docker run amir20/dozzle generate --help` displays all options.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

+12 -10
View File
@@ -4,12 +4,11 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/alexflint/go-arg v1.5.1
github.com/beme/abide v0.0.0-20190723115211-635a09831760
github.com/docker/docker v28.0.4+incompatible
github.com/docker/docker v28.1.1+incompatible
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1
github.com/gogo/protobuf v1.3.2 // indirect
github.com/magiconair/properties v1.8.9
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -18,23 +17,25 @@ require (
github.com/spf13/afero v1.14.0
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.10.0
golang.org/x/net v0.35.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/PuerkitoBio/goquery v1.10.2
github.com/PuerkitoBio/goquery v1.10.3
github.com/andybalholm/brotli v1.1.1
github.com/go-chi/chi/v5 v5.2.1
github.com/go-chi/jwtauth/v5 v5.3.3
github.com/go-faker/faker/v4 v4.6.0
github.com/gorilla/websocket v1.5.3
github.com/puzpuzpuz/xsync/v4 v4.0.0
github.com/rs/zerolog v1.34.0
github.com/samber/lo v1.49.1
github.com/wk8/go-ordered-map/v2 v2.1.8
github.com/yuin/goldmark v1.7.8
golang.org/x/crypto v0.36.0
golang.org/x/sync v0.12.0
github.com/yuin/goldmark v1.7.10
golang.org/x/crypto v0.37.0
golang.org/x/sync v0.13.0
google.golang.org/grpc v1.71.1
google.golang.org/protobuf v1.36.6
k8s.io/api v0.32.3
@@ -80,6 +81,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -96,8 +98,8 @@ require (
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
golang.org/x/oauth2 v0.26.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/term v0.31.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.10.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
+28 -20
View File
@@ -2,12 +2,14 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7O
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8=
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
github.com/PuerkitoBio/goquery v1.10.3 h1:pFYcNSqHxBD06Fpj/KsbStFRsgRATgnf3LeXiUkhzPo=
github.com/PuerkitoBio/goquery v1.10.3/go.mod h1:tMUX0zDMHXYlAQk6p35XxQMqMweEKB7iK7iLNd4RH4Y=
github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8Y=
github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8=
github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -32,8 +34,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvw
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -50,6 +52,8 @@ github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/jwtauth/v5 v5.3.3 h1:50Uzmacu35/ZP9ER2Ht6SazwPsnLQ9LRJy6zTZJpHEo=
github.com/go-chi/jwtauth/v5 v5.3.3/go.mod h1:O4QvPRuZLZghl9WvfVaON+ARfGzpD2PBX/QY5vUz7aQ=
github.com/go-faker/faker/v4 v4.6.0 h1:6aOPzNptRiDwD14HuAnEtlTa+D1IfFuEHO8+vEFwjTs=
github.com/go-faker/faker/v4 v4.6.0/go.mod h1:ZmrHuVtTTm2Em9e0Du6CJ9CADaLEzGXW62z1YqFH0m0=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -113,8 +117,6 @@ github.com/lestrrat-go/jwx/v2 v2.1.3 h1:Ud4lb2QuxRClYAmRleF50KrbKIoM1TddXgBrneT5
github.com/lestrrat-go/jwx/v2 v2.1.3/go.mod h1:q6uFgbgZfEmQrfJfrCo90QcQOcXFMfbI/fO0NqRtvZo=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
@@ -128,6 +130,10 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -189,11 +195,13 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark v1.7.10 h1:S+LrtBjRmqMac2UdtB6yyCEJm+UILZ2fefI4p7o0QpI=
github.com/yuin/goldmark v1.7.10/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
@@ -222,8 +230,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -244,8 +252,8 @@ golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -257,8 +265,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -275,8 +283,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -286,8 +294,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -297,8 +305,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+3 -69
View File
@@ -14,7 +14,6 @@ import (
"github.com/amir20/dozzle/internal/agent/pb"
"github.com/amir20/dozzle/internal/container"
"github.com/amir20/dozzle/internal/utils"
"github.com/rs/zerolog/log"
orderedmap "github.com/wk8/go-ordered-map/v2"
"google.golang.org/grpc"
@@ -253,21 +252,7 @@ func (c *Client) StreamNewContainers(ctx context.Context, containers chan<- cont
return rpcErrToErr(err)
}
containers <- container.Container{
ID: resp.Container.Id,
Name: resp.Container.Name,
Image: resp.Container.Image,
Labels: resp.Container.Labels,
Group: resp.Container.Group,
Created: resp.Container.Created.AsTime(),
State: resp.Container.State,
Health: resp.Container.Health,
Host: resp.Container.Host,
Tty: resp.Container.Tty,
StartedAt: resp.Container.Started.AsTime(),
FinishedAt: resp.Container.Finished.AsTime(),
Command: resp.Container.Command,
}
containers <- container.FromProto(resp.Container)
}
}
@@ -277,33 +262,7 @@ func (c *Client) FindContainer(ctx context.Context, containerID string) (contain
return container.Container{}, err
}
var stats []container.ContainerStat
for _, stat := range response.Container.Stats {
stats = append(stats, container.ContainerStat{
ID: stat.Id,
CPUPercent: stat.CpuPercent,
MemoryPercent: stat.MemoryPercent,
MemoryUsage: stat.MemoryUsage,
})
}
return container.Container{
ID: response.Container.Id,
Name: response.Container.Name,
Image: response.Container.Image,
Labels: response.Container.Labels,
Group: response.Container.Group,
Created: response.Container.Created.AsTime(),
State: response.Container.State,
Health: response.Container.Health,
Host: response.Container.Host,
Tty: response.Container.Tty,
Command: response.Container.Command,
StartedAt: response.Container.Started.AsTime(),
FinishedAt: response.Container.Finished.AsTime(),
Stats: utils.RingBufferFrom(300, stats),
}, nil
return container.FromProto(response.Container), nil
}
func (c *Client) ListContainers(ctx context.Context, labels container.ContainerLabels) ([]container.Container, error) {
@@ -323,32 +282,7 @@ func (c *Client) ListContainers(ctx context.Context, labels container.ContainerL
containers := make([]container.Container, 0)
for _, c := range response.Containers {
var stats []container.ContainerStat
for _, stat := range c.Stats {
stats = append(stats, container.ContainerStat{
ID: stat.Id,
CPUPercent: stat.CpuPercent,
MemoryPercent: stat.MemoryPercent,
MemoryUsage: stat.MemoryUsage,
})
}
containers = append(containers, container.Container{
ID: c.Id,
Name: c.Name,
Image: c.Image,
Labels: c.Labels,
Group: c.Group,
Created: c.Created.AsTime(),
State: c.State,
Health: c.Health,
Host: c.Host,
Tty: c.Tty,
Command: c.Command,
StartedAt: c.Started.AsTime(),
FinishedAt: c.Finished.AsTime(),
Stats: utils.RingBufferFrom(300, stats),
})
containers = append(containers, container.FromProto(c))
}
return containers, nil
+17 -58
View File
@@ -3,6 +3,7 @@ package agent
import (
"context"
"crypto/tls"
"fmt"
"io"
"net"
"os"
@@ -13,6 +14,8 @@ import (
"github.com/amir20/dozzle/internal/container"
"github.com/amir20/dozzle/internal/utils"
"github.com/docker/docker/api/types/system"
"github.com/go-faker/faker/v4"
"github.com/go-faker/faker/v4/pkg/options"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@@ -78,7 +81,16 @@ func (m *MockedClient) SystemInfo() system.Info {
return system.Info{ID: "123"}
}
var wantedContainer = container.Container{}
func init() {
faker.FakeData(&wantedContainer, options.WithFieldsToIgnore("Stats"))
wantedContainer.FinishedAt = wantedContainer.FinishedAt.UTC()
wantedContainer.Created = wantedContainer.Created.UTC()
wantedContainer.StartedAt = wantedContainer.StartedAt.UTC()
wantedContainer.Stats = utils.NewRingBuffer[container.ContainerStat](300)
fmt.Printf("Fake data generated %+v", wantedContainer)
lis = bufconn.Listen(bufSize)
cwd, err := os.Getwd()
@@ -111,27 +123,8 @@ func init() {
time.Sleep(5 * time.Second)
})
client.On("FindContainer", mock.Anything, "123456").Return(container.Container{
ID: "123456",
Name: "test",
Host: "localhost",
Image: "test",
State: "running",
Health: "healthy",
Group: "test",
Command: "test",
Tty: true,
Labels: map[string]string{
"test": "test",
},
Stats: utils.NewRingBuffer[container.ContainerStat](300),
Created: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
StartedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
FinishedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
}, nil)
client.On("FindContainer", mock.Anything, "123456").Return(wantedContainer, nil)
server, _ := NewServer(client, certs, "test", container.ContainerLabels{})
go server.Serve(lis)
}
@@ -147,24 +140,7 @@ func TestFindContainer(t *testing.T) {
c, _ := rpc.FindContainer(context.Background(), "123456")
assert.Equal(t, c, container.Container{
ID: "123456",
Name: "test",
Host: "localhost",
Image: "test",
State: "running",
Health: "healthy",
Group: "test",
Command: "test",
Tty: true,
Labels: map[string]string{
"test": "test",
},
Stats: utils.NewRingBuffer[container.ContainerStat](300),
Created: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
StartedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
FinishedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
})
assert.Equal(t, wantedContainer, c)
}
func TestListContainers(t *testing.T) {
@@ -175,24 +151,7 @@ func TestListContainers(t *testing.T) {
containers, _ := rpc.ListContainers(context.Background(), container.ContainerLabels{})
assert.Equal(t, containers, []container.Container{
{
ID: "123456",
Name: "test",
Host: "localhost",
Image: "test",
State: "running",
Health: "healthy",
Group: "test",
Command: "test",
Tty: true,
Labels: map[string]string{
"test": "test",
},
Stats: utils.NewRingBuffer[container.ContainerStat](300),
Created: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
StartedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
FinishedAt: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
},
})
assert.Equal(t, []container.Container{
wantedContainer,
}, containers)
}
+189 -76
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc-gen-go v1.36.5
// protoc v5.29.3
// source: rpc.proto
@@ -1048,81 +1048,194 @@ func (x *ContainerExecResponse) GetStdout() []byte {
var File_rpc_proto protoreflect.FileDescriptor
const file_rpc_proto_rawDesc = "" +
"\n" +
"\trpc.proto\x12\bprotobuf\x1a\vtypes.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xb1\x01\n" +
"\x15ListContainersRequest\x12C\n" +
"\x06filter\x18\x01 \x03(\v2+.protobuf.ListContainersRequest.FilterEntryR\x06filter\x1aS\n" +
"\vFilterEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12.\n" +
"\x05value\x18\x02 \x01(\v2\x18.protobuf.RepeatedStringR\x05value:\x028\x01\"(\n" +
"\x0eRepeatedString\x12\x16\n" +
"\x06values\x18\x01 \x03(\tR\x06values\"M\n" +
"\x16ListContainersResponse\x123\n" +
"\n" +
"containers\x18\x01 \x03(\v2\x13.protobuf.ContainerR\n" +
"containers\"\xd1\x01\n" +
"\x14FindContainerRequest\x12 \n" +
"\vcontainerId\x18\x01 \x01(\tR\vcontainerId\x12B\n" +
"\x06filter\x18\x02 \x03(\v2*.protobuf.FindContainerRequest.FilterEntryR\x06filter\x1aS\n" +
"\vFilterEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12.\n" +
"\x05value\x18\x02 \x01(\v2\x18.protobuf.RepeatedStringR\x05value:\x028\x01\"J\n" +
"\x15FindContainerResponse\x121\n" +
"\tcontainer\x18\x01 \x01(\v2\x13.protobuf.ContainerR\tcontainer\"\x89\x01\n" +
"\x11StreamLogsRequest\x12 \n" +
"\vcontainerId\x18\x01 \x01(\tR\vcontainerId\x120\n" +
"\x05since\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x05since\x12 \n" +
"\vstreamTypes\x18\x03 \x01(\x05R\vstreamTypes\">\n" +
"\x12StreamLogsResponse\x12(\n" +
"\x05event\x18\x01 \x01(\v2\x12.protobuf.LogEventR\x05event\"\xc1\x01\n" +
"\x17LogsBetweenDatesRequest\x12 \n" +
"\vcontainerId\x18\x01 \x01(\tR\vcontainerId\x120\n" +
"\x05since\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x05since\x120\n" +
"\x05until\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x05until\x12 \n" +
"\vstreamTypes\x18\x04 \x01(\x05R\vstreamTypes\"\xbf\x01\n" +
"\x15StreamRawBytesRequest\x12 \n" +
"\vcontainerId\x18\x01 \x01(\tR\vcontainerId\x120\n" +
"\x05since\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x05since\x120\n" +
"\x05until\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x05until\x12 \n" +
"\vstreamTypes\x18\x04 \x01(\x05R\vstreamTypes\",\n" +
"\x16StreamRawBytesResponse\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\"\x15\n" +
"\x13StreamEventsRequest\"F\n" +
"\x14StreamEventsResponse\x12.\n" +
"\x05event\x18\x01 \x01(\v2\x18.protobuf.ContainerEventR\x05event\"\x14\n" +
"\x12StreamStatsRequest\"B\n" +
"\x13StreamStatsResponse\x12+\n" +
"\x04stat\x18\x01 \x01(\v2\x17.protobuf.ContainerStatR\x04stat\"\x11\n" +
"\x0fHostInfoRequest\"6\n" +
"\x10HostInfoResponse\x12\"\n" +
"\x04host\x18\x01 \x01(\v2\x0e.protobuf.HostR\x04host\"\x1f\n" +
"\x1dStreamContainerStartedRequest\"S\n" +
"\x1eStreamContainerStartedResponse\x121\n" +
"\tcontainer\x18\x01 \x01(\v2\x13.protobuf.ContainerR\tcontainer\"m\n" +
"\x16ContainerActionRequest\x12 \n" +
"\vcontainerId\x18\x01 \x01(\tR\vcontainerId\x121\n" +
"\x06action\x18\x02 \x01(\x0e2\x19.protobuf.ContainerActionR\x06action\"\x19\n" +
"\x17ContainerActionResponse\"h\n" +
"\x14ContainerExecRequest\x12 \n" +
"\vcontainerId\x18\x01 \x01(\tR\vcontainerId\x12\x18\n" +
"\acommand\x18\x02 \x03(\tR\acommand\x12\x14\n" +
"\x05stdin\x18\x03 \x01(\fR\x05stdin\"/\n" +
"\x15ContainerExecResponse\x12\x16\n" +
"\x06stdout\x18\x01 \x01(\fR\x06stdout2\xc3\a\n" +
"\fAgentService\x12U\n" +
"\x0eListContainers\x12\x1f.protobuf.ListContainersRequest\x1a .protobuf.ListContainersResponse\"\x00\x12R\n" +
"\rFindContainer\x12\x1e.protobuf.FindContainerRequest\x1a\x1f.protobuf.FindContainerResponse\"\x00\x12K\n" +
"\n" +
"StreamLogs\x12\x1b.protobuf.StreamLogsRequest\x1a\x1c.protobuf.StreamLogsResponse\"\x000\x01\x12W\n" +
"\x10LogsBetweenDates\x12!.protobuf.LogsBetweenDatesRequest\x1a\x1c.protobuf.StreamLogsResponse\"\x000\x01\x12W\n" +
"\x0eStreamRawBytes\x12\x1f.protobuf.StreamRawBytesRequest\x1a .protobuf.StreamRawBytesResponse\"\x000\x01\x12Q\n" +
"\fStreamEvents\x12\x1d.protobuf.StreamEventsRequest\x1a\x1e.protobuf.StreamEventsResponse\"\x000\x01\x12N\n" +
"\vStreamStats\x12\x1c.protobuf.StreamStatsRequest\x1a\x1d.protobuf.StreamStatsResponse\"\x000\x01\x12o\n" +
"\x16StreamContainerStarted\x12'.protobuf.StreamContainerStartedRequest\x1a(.protobuf.StreamContainerStartedResponse\"\x000\x01\x12C\n" +
"\bHostInfo\x12\x19.protobuf.HostInfoRequest\x1a\x1a.protobuf.HostInfoResponse\"\x00\x12X\n" +
"\x0fContainerAction\x12 .protobuf.ContainerActionRequest\x1a!.protobuf.ContainerActionResponse\"\x00\x12V\n" +
"\rContainerExec\x12\x1e.protobuf.ContainerExecRequest\x1a\x1f.protobuf.ContainerExecResponse\"\x00(\x010\x01B\x13Z\x11internal/agent/pbb\x06proto3"
var file_rpc_proto_rawDesc = string([]byte{
0x0a, 0x09, 0x72, 0x70, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x1a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0xb1, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x43, 0x0a,
0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46,
0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74,
0x65, 0x72, 0x1a, 0x53, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65,
0x70, 0x65, 0x61, 0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x28, 0x0a, 0x0e, 0x52, 0x65, 0x70, 0x65, 0x61,
0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x73, 0x22, 0x4d, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73,
0x22, 0xd1, 0x01, 0x0a, 0x14, 0x46, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x42, 0x0a, 0x06, 0x66,
0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x69, 0x6c, 0x74,
0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x1a,
0x53, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x70, 0x65, 0x61,
0x74, 0x65, 0x64, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x3a, 0x02, 0x38, 0x01, 0x22, 0x4a, 0x0a, 0x15, 0x46, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a,
0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
0x22, 0x89, 0x01, 0x0a, 0x11, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69, 0x6e, 0x63,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52,
0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x73, 0x22, 0x3e, 0x0a, 0x12,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x6f, 0x67,
0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0xc1, 0x01, 0x0a,
0x17, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x44, 0x61, 0x74, 0x65,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74,
0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63,
0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x05, 0x73, 0x69,
0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x30, 0x0a, 0x05,
0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x12, 0x20,
0x0a, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x73, 0x18, 0x04, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x73,
0x22, 0xbf, 0x01, 0x0a, 0x15, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x61, 0x77, 0x42, 0x79,
0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f,
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x05,
0x73, 0x69, 0x6e, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x73, 0x69, 0x6e, 0x63, 0x65, 0x12, 0x30,
0x0a, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c,
0x12, 0x20, 0x0a, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x73, 0x18,
0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70,
0x65, 0x73, 0x22, 0x2c, 0x0a, 0x16, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x61, 0x77, 0x42,
0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04,
0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61,
0x22, 0x15, 0x0a, 0x13, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x46, 0x0a, 0x14, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x2e, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22,
0x14, 0x0a, 0x12, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x42, 0x0a, 0x13, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53,
0x74, 0x61, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04,
0x73, 0x74, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53,
0x74, 0x61, 0x74, 0x52, 0x04, 0x73, 0x74, 0x61, 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x48, 0x6f, 0x73,
0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x36, 0x0a, 0x10,
0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x12, 0x22, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x04,
0x68, 0x6f, 0x73, 0x74, 0x22, 0x1f, 0x0a, 0x1d, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f,
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x53, 0x0a, 0x1e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43,
0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52,
0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x22, 0x6d, 0x0a, 0x16, 0x43, 0x6f,
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x68, 0x0a, 0x14, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b,
0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18,
0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x64, 0x69,
0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x64, 0x69, 0x6e, 0x22, 0x2f,
0x0a, 0x15, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x32,
0xc3, 0x07, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x55, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x73, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c,
0x69, 0x73, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0d, 0x46, 0x69, 0x6e, 0x64, 0x43,
0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0a, 0x53,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x10, 0x4c, 0x6f, 0x67, 0x73,
0x42, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x73, 0x12, 0x21, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x6f, 0x67, 0x73, 0x42, 0x65, 0x74, 0x77,
0x65, 0x65, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61,
0x6d, 0x4c, 0x6f, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30,
0x01, 0x12, 0x57, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x61, 0x77, 0x42, 0x79,
0x74, 0x65, 0x73, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53,
0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x61, 0x77, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x61, 0x77, 0x42, 0x79, 0x74, 0x65, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x51, 0x0a, 0x0c, 0x53, 0x74,
0x72, 0x65, 0x61, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x4e, 0x0a,
0x0b, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74,
0x61, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x53, 0x74, 0x61, 0x74,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x6f, 0x0a,
0x16, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x65,
0x61, 0x6d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x72, 0x74,
0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x43,
0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74,
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x56, 0x0a,
0x0d, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x12, 0x1e,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69,
0x6e, 0x65, 0x72, 0x45, 0x78, 0x65, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x13, 0x5a, 0x11, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
})
var (
file_rpc_proto_rawDescOnce sync.Once
+145 -70
View File
@@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.6
// protoc-gen-go v1.36.5
// protoc v5.29.3
// source: types.proto
@@ -90,6 +90,9 @@ type Container struct {
Group string `protobuf:"bytes,14,opt,name=group,proto3" json:"group,omitempty"`
Command string `protobuf:"bytes,15,opt,name=command,proto3" json:"command,omitempty"`
Finished *timestamppb.Timestamp `protobuf:"bytes,16,opt,name=finished,proto3" json:"finished,omitempty"`
MemoryLimit uint64 `protobuf:"varint,17,opt,name=memoryLimit,proto3" json:"memoryLimit,omitempty"`
CpuLimit float64 `protobuf:"fixed64,18,opt,name=cpuLimit,proto3" json:"cpuLimit,omitempty"`
FullyLoaded bool `protobuf:"varint,19,opt,name=fullyLoaded,proto3" json:"fullyLoaded,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
@@ -236,6 +239,27 @@ func (x *Container) GetFinished() *timestamppb.Timestamp {
return nil
}
func (x *Container) GetMemoryLimit() uint64 {
if x != nil {
return x.MemoryLimit
}
return 0
}
func (x *Container) GetCpuLimit() float64 {
if x != nil {
return x.CpuLimit
}
return 0
}
func (x *Container) GetFullyLoaded() bool {
if x != nil {
return x.FullyLoaded
}
return false
}
type ContainerStat struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
@@ -686,75 +710,126 @@ func (x *Host) GetDockerVersion() string {
var File_types_proto protoreflect.FileDescriptor
const file_types_proto_rawDesc = "" +
"\n" +
"\vtypes.proto\x12\bprotobuf\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19google/protobuf/any.proto\"\xc2\x04\n" +
"\tContainer\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
"\x04name\x18\x02 \x01(\tR\x04name\x12\x14\n" +
"\x05image\x18\x03 \x01(\tR\x05image\x12\x16\n" +
"\x06status\x18\x04 \x01(\tR\x06status\x12\x14\n" +
"\x05state\x18\x05 \x01(\tR\x05state\x12\x18\n" +
"\aImageId\x18\x06 \x01(\tR\aImageId\x124\n" +
"\acreated\x18\a \x01(\v2\x1a.google.protobuf.TimestampR\acreated\x124\n" +
"\astarted\x18\b \x01(\v2\x1a.google.protobuf.TimestampR\astarted\x12\x16\n" +
"\x06health\x18\t \x01(\tR\x06health\x12\x12\n" +
"\x04host\x18\n" +
" \x01(\tR\x04host\x12\x10\n" +
"\x03tty\x18\v \x01(\bR\x03tty\x127\n" +
"\x06labels\x18\f \x03(\v2\x1f.protobuf.Container.LabelsEntryR\x06labels\x12-\n" +
"\x05stats\x18\r \x03(\v2\x17.protobuf.ContainerStatR\x05stats\x12\x14\n" +
"\x05group\x18\x0e \x01(\tR\x05group\x12\x18\n" +
"\acommand\x18\x0f \x01(\tR\acommand\x126\n" +
"\bfinished\x18\x10 \x01(\v2\x1a.google.protobuf.TimestampR\bfinished\x1a9\n" +
"\vLabelsEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x87\x01\n" +
"\rContainerStat\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x1e\n" +
"\n" +
"cpuPercent\x18\x02 \x01(\x01R\n" +
"cpuPercent\x12 \n" +
"\vmemoryUsage\x18\x03 \x01(\x01R\vmemoryUsage\x12$\n" +
"\rmemoryPercent\x18\x04 \x01(\x01R\rmemoryPercent\"\xf0\x01\n" +
"\bLogEvent\x12\x0e\n" +
"\x02id\x18\x01 \x01(\rR\x02id\x12 \n" +
"\vcontainerId\x18\x02 \x01(\tR\vcontainerId\x12.\n" +
"\amessage\x18\x03 \x01(\v2\x14.google.protobuf.AnyR\amessage\x128\n" +
"\ttimestamp\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\x12\x14\n" +
"\x05level\x18\x05 \x01(\tR\x05level\x12\x16\n" +
"\x06stream\x18\x06 \x01(\tR\x06stream\x12\x1a\n" +
"\bposition\x18\a \x01(\tR\bposition\")\n" +
"\rSimpleMessage\x12\x18\n" +
"\amessage\x18\x01 \x01(\tR\amessage\"$\n" +
"\x0eComplexMessage\x12\x12\n" +
"\x04data\x18\x01 \x01(\fR\x04data\"\x8c\x01\n" +
"\x0eContainerEvent\x12\x18\n" +
"\aactorId\x18\x01 \x01(\tR\aactorId\x12\x12\n" +
"\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
"\x04host\x18\x03 \x01(\tR\x04host\x128\n" +
"\ttimestamp\x18\x04 \x01(\v2\x1a.google.protobuf.TimestampR\ttimestamp\"\xaf\x03\n" +
"\x04Host\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
"\x04name\x18\x02 \x01(\tR\x04name\x12 \n" +
"\vnodeAddress\x18\x03 \x01(\tR\vnodeAddress\x12\x14\n" +
"\x05swarm\x18\x04 \x01(\bR\x05swarm\x122\n" +
"\x06labels\x18\x05 \x03(\v2\x1a.protobuf.Host.LabelsEntryR\x06labels\x12(\n" +
"\x0foperatingSystem\x18\x06 \x01(\tR\x0foperatingSystem\x12\x1c\n" +
"\tosVersion\x18\a \x01(\tR\tosVersion\x12\x16\n" +
"\x06osType\x18\b \x01(\tR\x06osType\x12\x1a\n" +
"\bcpuCores\x18\t \x01(\rR\bcpuCores\x12\x16\n" +
"\x06memory\x18\n" +
" \x01(\x04R\x06memory\x12\"\n" +
"\fagentVersion\x18\v \x01(\tR\fagentVersion\x12$\n" +
"\rdockerVersion\x18\f \x01(\tR\rdockerVersion\x1a9\n" +
"\vLabelsEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01*3\n" +
"\x0fContainerAction\x12\t\n" +
"\x05Start\x10\x00\x12\b\n" +
"\x04Stop\x10\x01\x12\v\n" +
"\aRestart\x10\x02B\x13Z\x11internal/agent/pbb\x06proto3"
var file_types_proto_rawDesc = string([]byte{
0x0a, 0x0b, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x22, 0xa2, 0x05, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73,
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x49, 0x6d, 0x61,
0x67, 0x65, 0x49, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x49, 0x6d, 0x61, 0x67,
0x65, 0x49, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x07,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x73, 0x74, 0x61,
0x72, 0x74, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12,
0x16, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
0x06, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18,
0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x74,
0x74, 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x74, 0x74, 0x79, 0x12, 0x37, 0x0a,
0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06,
0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x73, 0x18,
0x0d, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x52, 0x05,
0x73, 0x74, 0x61, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x0e,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x63,
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x36, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65,
0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x20, 0x0a,
0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x11, 0x20, 0x01,
0x28, 0x04, 0x52, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12,
0x1a, 0x0a, 0x08, 0x63, 0x70, 0x75, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28,
0x01, 0x52, 0x08, 0x63, 0x70, 0x75, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x66,
0x75, 0x6c, 0x6c, 0x79, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08,
0x52, 0x0b, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x4c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x1a, 0x39, 0x0a,
0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x87, 0x01, 0x0a, 0x0d, 0x43, 0x6f, 0x6e,
0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x70,
0x75, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0a,
0x63, 0x70, 0x75, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x65,
0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52,
0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x24, 0x0a, 0x0d,
0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20,
0x01, 0x28, 0x01, 0x52, 0x0d, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x50, 0x65, 0x72, 0x63, 0x65,
0x6e, 0x74, 0x22, 0xf0, 0x01, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12,
0x20, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x49,
0x64, 0x12, 0x2e, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x6c,
0x65, 0x76, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65,
0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x06, 0x20, 0x01, 0x28,
0x09, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x73,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x29, 0x0a, 0x0d, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x4d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
0x22, 0x24, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c,
0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x8c, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x74,
0x6f, 0x72, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f,
0x72, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18,
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x74,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0xaf, 0x03, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x0e,
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x6f, 0x64, 0x65, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x77, 0x61, 0x72, 0x6d, 0x18, 0x04, 0x20,
0x01, 0x28, 0x08, 0x52, 0x05, 0x73, 0x77, 0x61, 0x72, 0x6d, 0x12, 0x32, 0x0a, 0x06, 0x6c, 0x61,
0x62, 0x65, 0x6c, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c,
0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x28,
0x0a, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
0x6e, 0x67, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x73, 0x56, 0x65,
0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x73, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x73, 0x54, 0x79, 0x70, 0x65,
0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a,
0x0a, 0x08, 0x63, 0x70, 0x75, 0x43, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x08, 0x63, 0x70, 0x75, 0x43, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65,
0x6d, 0x6f, 0x72, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x65, 0x6d, 0x6f,
0x72, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0d, 0x64, 0x6f, 0x63, 0x6b, 0x65, 0x72,
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64,
0x6f, 0x63, 0x6b, 0x65, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x39, 0x0a, 0x0b,
0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x33, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61,
0x69, 0x6e, 0x65, 0x72, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x74,
0x61, 0x72, 0x74, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x74, 0x6f, 0x70, 0x10, 0x01, 0x12,
0x0b, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x10, 0x02, 0x42, 0x13, 0x5a, 0x11,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70,
0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
})
var (
file_types_proto_rawDescOnce sync.Once
+6 -57
View File
@@ -189,23 +189,9 @@ func (s *server) FindContainer(ctx context.Context, in *pb.FindContainerRequest)
if err != nil {
return nil, status.Error(codes.NotFound, err.Error())
}
c := container.ToProto()
return &pb.FindContainerResponse{
Container: &pb.Container{
Id: container.ID,
Name: container.Name,
Image: container.Image,
Command: container.Command,
Created: timestamppb.New(container.Created),
State: container.State,
Health: container.Health,
Host: container.Host,
Tty: container.Tty,
Labels: container.Labels,
Group: container.Group,
Started: timestamppb.New(container.StartedAt),
Finished: timestamppb.New(container.FinishedAt),
},
Container: &c,
}, nil
}
@@ -223,34 +209,9 @@ func (s *server) ListContainers(ctx context.Context, in *pb.ListContainersReques
}
var pbContainers []*pb.Container
for _, container := range containers {
var pbStats []*pb.ContainerStat
for _, stat := range container.Stats.Data() {
pbStats = append(pbStats, &pb.ContainerStat{
Id: stat.ID,
CpuPercent: stat.CPUPercent,
MemoryPercent: stat.MemoryPercent,
MemoryUsage: stat.MemoryUsage,
})
}
pbContainers = append(pbContainers, &pb.Container{
Id: container.ID,
Name: container.Name,
Image: container.Image,
Created: timestamppb.New(container.Created),
State: container.State,
Health: container.Health,
Host: container.Host,
Tty: container.Tty,
Labels: container.Labels,
Group: container.Group,
Started: timestamppb.New(container.StartedAt),
Finished: timestamppb.New(container.FinishedAt),
Stats: pbStats,
Command: container.Command,
})
c := container.ToProto()
pbContainers = append(pbContainers, &c)
}
return &pb.ListContainersResponse{
@@ -280,21 +241,9 @@ func (s *server) StreamContainerStarted(in *pb.StreamContainerStartedRequest, ou
for {
select {
case container := <-containers:
c := container.ToProto()
out.Send(&pb.StreamContainerStartedResponse{
Container: &pb.Container{
Id: container.ID,
Name: container.Name,
Image: container.Image,
Created: timestamppb.New(container.Created),
State: container.State,
Health: container.Health,
Host: container.Host,
Tty: container.Tty,
Labels: container.Labels,
Group: container.Group,
Started: timestamppb.New(container.StartedAt),
Finished: timestamppb.New(container.FinishedAt),
},
Container: &c,
})
case <-out.Context().Done():
return nil
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/amir20/dozzle/internal/utils"
"github.com/magiconair/properties/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
+69 -1
View File
@@ -6,7 +6,9 @@ import (
"strings"
"time"
"github.com/amir20/dozzle/internal/agent/pb"
"github.com/amir20/dozzle/internal/utils"
"google.golang.org/protobuf/types/known/timestamppb"
)
// Container represents an internal representation of docker containers
@@ -24,10 +26,76 @@ type Container struct {
Tty bool `json:"-"`
Labels map[string]string `json:"labels,omitempty"`
Stats *utils.RingBuffer[ContainerStat] `json:"stats,omitempty"`
MemoryLimit uint64 `json:"memoryLimit"`
CPULimit float64 `json:"cpuLimit"`
Group string `json:"group,omitempty"`
FullyLoaded bool `json:"-,omitempty"`
}
func (container Container) ToProto() pb.Container {
var pbStats []*pb.ContainerStat
for _, stat := range container.Stats.Data() {
pbStats = append(pbStats, &pb.ContainerStat{
Id: stat.ID,
CpuPercent: stat.CPUPercent,
MemoryPercent: stat.MemoryPercent,
MemoryUsage: stat.MemoryUsage,
})
}
return pb.Container{
Id: container.ID,
Name: container.Name,
Image: container.Image,
Created: timestamppb.New(container.Created),
State: container.State,
Health: container.Health,
Host: container.Host,
Tty: container.Tty,
Labels: container.Labels,
Group: container.Group,
Started: timestamppb.New(container.StartedAt),
Finished: timestamppb.New(container.FinishedAt),
Stats: pbStats,
Command: container.Command,
MemoryLimit: container.MemoryLimit,
CpuLimit: container.CPULimit,
FullyLoaded: container.FullyLoaded,
}
}
func FromProto(c *pb.Container) Container {
var stats []ContainerStat
for _, stat := range c.Stats {
stats = append(stats, ContainerStat{
ID: stat.Id,
CPUPercent: stat.CpuPercent,
MemoryPercent: stat.MemoryPercent,
MemoryUsage: stat.MemoryUsage,
})
}
return Container{
ID: c.Id,
Name: c.Name,
Image: c.Image,
Labels: c.Labels,
Group: c.Group,
Created: c.Created.AsTime(),
State: c.State,
Health: c.Health,
Host: c.Host,
Tty: c.Tty,
Command: c.Command,
StartedAt: c.Started.AsTime(),
FinishedAt: c.Finished.AsTime(),
Stats: utils.RingBufferFrom(300, stats),
MemoryLimit: c.MemoryLimit,
CPULimit: c.CpuLimit,
FullyLoaded: c.FullyLoaded,
}
}
// ContainerStat represent stats instant for a container
type ContainerStat struct {
ID string `json:"id"`
@@ -54,7 +122,7 @@ func ParseContainerFilter(commaValues string) (ContainerLabels, error) {
return filter, nil
}
for _, val := range strings.Split(commaValues, ",") {
for val := range strings.SplitSeq(commaValues, ",") {
pos := strings.Index(val, "=")
if pos == -1 {
return nil, fmt.Errorf("invalid filter: %s", filter)
+25
View File
@@ -0,0 +1,25 @@
package container
import (
"testing"
"github.com/amir20/dozzle/internal/utils"
"github.com/go-faker/faker/v4"
"github.com/go-faker/faker/v4/pkg/options"
"github.com/stretchr/testify/assert"
)
func TestProto(t *testing.T) {
expected := Container{}
faker.FakeData(&expected, options.WithFieldsToIgnore("Stats"))
expected.FinishedAt = expected.FinishedAt.UTC()
expected.Created = expected.Created.UTC()
expected.StartedAt = expected.StartedAt.UTC()
expected.Stats = utils.NewRingBuffer[ContainerStat](300)
pb := expected.ToProto()
actual := FromProto(&pb)
assert.Equal(t, expected, actual)
}
+2
View File
@@ -399,6 +399,8 @@ func newContainerFromJSON(c docker.InspectResponse, host string) container.Conta
Stats: utils.NewRingBuffer[container.ContainerStat](300), // 300 seconds of stats
Group: group,
Tty: c.Config.Tty,
MemoryLimit: uint64(c.HostConfig.Memory),
CPULimit: float64(c.HostConfig.NanoCPUs) / 1e9,
FullyLoaded: true,
}
+6 -2
View File
@@ -184,7 +184,11 @@ func Test_dockerClient_FindContainer_happy(t *testing.T) {
proxy := new(mockedProxy)
state := &docker.State{Status: "running", StartedAt: time.Now().Format(time.RFC3339Nano)}
json := docker.InspectResponse{ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijklmnopqrst", State: state}, Config: &docker.Config{Tty: false}}
json := docker.InspectResponse{
ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijklmnopqrst", State: state, HostConfig: &docker.HostConfig{}},
Config: &docker.Config{Tty: false},
}
proxy.On("ContainerInspect", mock.Anything, "abcdefghijkl").Return(json, nil)
client := &DockerClient{proxy, container.Host{ID: "localhost"}, system.Info{}}
@@ -213,7 +217,7 @@ func Test_dockerClient_ContainerActions_happy(t *testing.T) {
client := &DockerClient{proxy, container.Host{ID: "localhost"}, system.Info{}}
state := &docker.State{Status: "running", StartedAt: time.Now().Format(time.RFC3339Nano)}
json := docker.InspectResponse{ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijkl", State: state}, Config: &docker.Config{Tty: false}}
json := docker.InspectResponse{ContainerJSONBase: &docker.ContainerJSONBase{ID: "abcdefghijkl", State: state, HostConfig: &docker.HostConfig{}}, Config: &docker.Config{Tty: false}}
proxy.On("ContainerInspect", mock.Anything, "abcdefghijkl").Return(json, nil)
proxy.On("ContainerStart", mock.Anything, "abcdefghijkl", mock.Anything).Return(nil)
+2 -2
View File
@@ -15,7 +15,6 @@ import (
"github.com/rs/zerolog/log"
)
type AgentCmd struct {
Addr string `arg:"--agent-addr,env:DOZZLE_AGENT_ADDR" default:":7007" help:"sets the host:port to bind for the agent"`
}
@@ -37,11 +36,12 @@ func (a *AgentCmd) Run(args Args, embeddedCerts embed.FS) error {
if err != nil {
return fmt.Errorf("failed to listen: %w", err)
}
tempFile, err := os.CreateTemp("./", "agent-*.addr")
tempFile, err := os.CreateTemp("", "agent-*.addr")
if err != nil {
return fmt.Errorf("failed to create temp file: %w", err)
}
io.WriteString(tempFile, listener.Addr().String())
log.Debug().Str("file", tempFile.Name()).Msg("Created temp file")
go StartEvent(args, "", client, "agent")
server, err := agent.NewServer(client, certs, args.Version(), args.Filter)
if err != nil {
+4
View File
@@ -6,6 +6,8 @@ import (
"os"
"github.com/amir20/dozzle/internal/auth"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
type GenerateCmd struct {
@@ -17,6 +19,8 @@ type GenerateCmd struct {
}
func (g *GenerateCmd) Run(args Args, embeddedCerts embed.FS) error {
writer := zerolog.NewConsoleWriter()
log.Logger = log.Output(writer)
StartEvent(args, "", nil, "generate")
if args.Generate.Username == "" || args.Generate.Password == "" {
return fmt.Errorf("username and password are required")
+12 -27
View File
@@ -8,43 +8,28 @@ import (
"path/filepath"
"github.com/amir20/dozzle/internal/healthcheck"
"github.com/rs/zerolog/log"
)
type HealthcheckCmd struct {
}
type HealthcheckCmd struct{}
func (h *HealthcheckCmd) Run(args Args, embeddedCerts embed.FS) error {
files, err := os.ReadDir(".")
if err != nil {
return fmt.Errorf("failed to read directory: %w", err)
}
agentAddress := ""
for _, file := range files {
if match, _ := filepath.Match("agent-*.addr", file.Name()); match {
data, err := os.ReadFile(file.Name())
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
agentAddress = string(data)
break
if matches, err := filepath.Glob("/tmp/agent-*.addr"); err == nil && len(matches) == 1 {
data, err := os.ReadFile(matches[0])
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
}
if agentAddress == "" {
if err := healthcheck.HttpRequest(args.Addr, args.Base); err != nil {
return fmt.Errorf("failed to make request: %w", err)
}
} else {
agentAddress := string(data)
certs, err := ReadCertificates(embeddedCerts)
if err != nil {
return fmt.Errorf("failed to read certificates: %w", err)
}
ctx, cancel := context.WithTimeout(context.Background(), args.Timeout)
defer cancel()
if err := healthcheck.RPCRequest(ctx, agentAddress, certs); err != nil {
return fmt.Errorf("failed to make request: %w", err)
}
log.Info().Str("address", agentAddress).Msg("Making RPC request to agent")
return healthcheck.RPCRequest(ctx, agentAddress, certs)
} else {
log.Info().Str("address", args.Addr).Str("base", args.Base).Msg("Making HTTP request to server")
return healthcheck.HttpRequest(args.Addr, args.Base)
}
return nil
}
@@ -39,7 +39,7 @@ func NewRetriableClientManager(agents []string, timeout time.Duration, certs tls
}
if _, ok := clientMap[host.ID]; ok {
log.Warn().Str("host", host.Name).Msg("duplicate client found")
log.Warn().Str("name", host.Name).Str("id", host.ID).Msg("An agent with an existing ID was found. Removing the duplicate host. For more details, see http://localhost:5173/guide/agent#agent-not-showing-up.")
} else {
clientMap[host.ID] = client
}
@@ -64,7 +64,7 @@ func NewRetriableClientManager(agents []string, timeout time.Duration, certs tls
}
if _, ok := clientMap[host.ID]; ok {
log.Warn().Str("host", host.Name).Str("id", host.ID).Msg("duplicate host with same ID found")
log.Warn().Str("name", host.Name).Str("id", host.ID).Msg("An agent with an existing ID was found. Removing the duplicate host. For more details, see http://localhost:5173/guide/agent#agent-not-showing-up.")
} else {
clientMap[host.ID] = container_support.NewAgentService(agent)
}
+27 -7
View File
@@ -2,26 +2,27 @@ package support_web
import (
"bytes"
"compress/gzip"
"context"
"encoding/json"
"fmt"
"io"
"strings"
"net/http"
)
type SSEWriter struct {
w io.Writer
f http.Flusher
w http.ResponseWriter
}
type HasId interface {
MessageId() int64
}
func NewSSEWriter(ctx context.Context, w http.ResponseWriter) (*SSEWriter, error) {
f, ok := w.(http.Flusher)
if !ok {
func NewSSEWriter(ctx context.Context, w http.ResponseWriter, r *http.Request) (*SSEWriter, error) {
if _, ok := w.(http.Flusher); !ok {
return nil, http.ErrNotSupported
}
@@ -31,9 +32,15 @@ func NewSSEWriter(ctx context.Context, w http.ResponseWriter) (*SSEWriter, error
w.Header().Set("Connection", "keep-alive")
w.Header().Set("X-Accel-Buffering", "no")
var writer io.Writer = w
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
writer = gzip.NewWriter(w)
}
sse := &SSEWriter{
f: f,
w: w,
w: writer,
f: w.(http.Flusher),
}
return sse, nil
@@ -50,6 +57,13 @@ func (s *SSEWriter) Write(data []byte) (int, error) {
return written, err
}
if f, ok := s.w.(*gzip.Writer); ok {
err := f.Flush()
if err != nil {
return written, err
}
}
s.f.Flush()
return written, nil
@@ -60,6 +74,12 @@ func (s *SSEWriter) Ping() error {
return err
}
func (s *SSEWriter) Close() {
if closer, ok := s.w.(io.Closer); ok && s.w != nil {
closer.Close()
}
}
func (s *SSEWriter) Message(data any) error {
encoded, err := json.Marshal(data)
+2 -2
View File
@@ -13,7 +13,7 @@ import (
"github.com/amir20/dozzle/internal/auth"
"github.com/beme/abide"
"github.com/magiconair/properties/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/spf13/afero"
@@ -86,7 +86,7 @@ func Test_createRoutes_simple_valid_token(t *testing.T) {
assert.Equal(t, rr.Code, 200)
cookie := rr.Header().Get("Set-Cookie")
assert.Matches(t, cookie, "jwt=.+")
assert.Regexp(t, `jwt=.+`, cookie)
}
func Test_createRoutes_simple_bad_password(t *testing.T) {
+1 -2
View File
@@ -6,9 +6,8 @@ import (
"testing"
"github.com/magiconair/properties/assert"
"github.com/beme/abide"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/spf13/afero"
+37
View File
@@ -0,0 +1,37 @@
package web
import (
"io"
"net/http"
"strings"
"github.com/andybalholm/brotli"
)
type brotliWriter struct {
io.Writer
http.ResponseWriter
}
func (w brotliWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
func Brotli(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check if client supports Brotli
if !strings.Contains(r.Header.Get("Accept-Encoding"), "br") {
next.ServeHTTP(w, r)
return
}
w.Header().Set("Content-Encoding", "br")
w.Header().Add("Vary", "Accept-Encoding")
brWriter := brotli.NewWriter(w)
defer brWriter.Close()
bw := brotliWriter{Writer: brWriter, ResponseWriter: w}
next.ServeHTTP(bw, r)
})
}
+3 -1
View File
@@ -13,7 +13,9 @@ import (
)
func (h *handler) streamEvents(w http.ResponseWriter, r *http.Request) {
sseWriter, err := support_web.NewSSEWriter(r.Context(), w)
sseWriter, err := support_web.NewSSEWriter(r.Context(), w, r)
defer sseWriter.Close()
if err != nil {
log.Error().Err(err).Msg("error creating sse writer")
http.Error(w, err.Error(), http.StatusInternalServerError)
+1 -11
View File
@@ -3,10 +3,7 @@ package web
import (
"html/template"
"io"
"mime"
"path/filepath"
"sort"
"strings"
"encoding/json"
@@ -24,14 +21,7 @@ func (h *handler) index(w http.ResponseWriter, req *http.Request) {
_, err := h.content.Open(path)
if err == nil && req.URL.Path != "" && req.URL.Path != "/" {
w.Header().Set("Cache-Control", "max-age=31536000, immutable")
// if brotli is enabled, then just send over the compressed file
if file, err := h.content.Open(path + ".br"); strings.Contains(req.Header.Get("Accept-Encoding"), "br") && err == nil {
w.Header().Set("Content-Encoding", "br")
w.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(path)))
io.Copy(w, file)
} else {
fileServer.ServeHTTP(w, req)
}
fileServer.ServeHTTP(w, req)
} else {
h.executeTemplate(w, req)
}
+9 -1
View File
@@ -1,6 +1,7 @@
package web
import (
"compress/gzip"
"context"
"errors"
"regexp"
@@ -112,6 +113,12 @@ func (h *handler) fetchLogsBetweenDates(w http.ResponseWriter, r *http.Request)
}
encoder := json.NewEncoder(w)
if strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
w.Header().Set("Content-Encoding", "gzip")
writer := gzip.NewWriter(w)
defer writer.Close()
encoder = json.NewEncoder(writer)
}
for {
if buffer.Len() > minimum {
@@ -238,7 +245,8 @@ func (h *handler) streamLogsForContainers(w http.ResponseWriter, r *http.Request
return
}
sseWriter, err := support_web.NewSSEWriter(r.Context(), w)
sseWriter, err := support_web.NewSSEWriter(r.Context(), w, r)
defer sseWriter.Close()
if err != nil {
log.Error().Err(err).Msg("error creating sse writer")
http.Error(w, err.Error(), http.StatusInternalServerError)
+1 -1
View File
@@ -140,7 +140,7 @@ func createRouter(h *handler) *chi.Mux {
r.Get("/healthcheck", h.healthcheck)
defaultHandler := http.StripPrefix(strings.Replace(base+"/", "//", "/", 1), http.HandlerFunc(h.index))
r.Get("/*", func(w http.ResponseWriter, req *http.Request) {
r.With(Brotli).Get("/*", func(w http.ResponseWriter, req *http.Request) {
defaultHandler.ServeHTTP(w, req)
})
})
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: Kopieret
message: Log kopieret til clipboard
analytics:
creating_table: Opretter midlertidig tabel...
downloading: Henter containerlogfiler... ({size})
evaluating_query: Evaluerer forespørgsel...
total_records: I alt {count} poster.
showing_first: Viser de første {count}.
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: Kopiert
message: Log in Zwischenablage kopiert
analytics:
creating_table: Temporäre Tabelle wird erstellt...
downloading: Container-Logs werden abgerufen... ({size})
evaluating_query: Abfrage wird ausgewertet...
total_records: Insgesamt {count} Datensätze.
showing_first: Zeige die ersten {count}.
+6
View File
@@ -119,3 +119,9 @@ toasts:
copied:
title: Copied
message: Log copied to clipboard
analytics:
creating_table: Creating temporary table...
downloading: Fetching container logs... ({size})
evaluating_query: Evaluating query...
total_records: Total {count} records.
showing_first: Showing first {count}.
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: Copiado
message: Registro copiado al portapapeles
analytics:
creating_table: Creando tabla temporal...
downloading: Obteniendo registros de contenedores... ({size})
evaluating_query: Evaluando consulta...
total_records: Total {count} registros.
showing_first: Mostrando los primeros {count}.
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: Copié
message: Journal copié dans le presse-papiers
analytics:
creating_table: Création d'une table temporaire...
downloading: Récupération des journaux des conteneurs... ({size})
evaluating_query: Évaluation de la requête...
total_records: Total de {count} enregistrements.
showing_first: Affichage des {count} premiers.
+25 -19
View File
@@ -25,8 +25,8 @@ label:
created: Creato
avg-cpu: CPU (%)
avg-mem: MEM (%)
pinned: Spuntato
per-page: Rows per page
pinned: Fissato
per-page: Righe per pagina
host-menu: Host e Container
swarm-menu: Servizi e Stack
group-menu: Gruppi Personalizzati
@@ -52,20 +52,20 @@ error:
alert:
redirected:
title: Reindirizzamento ad un nuovo container
message: Dozzle automaticamente si è reindirizzato ad un nuovo container {containerId}.
message: Dozzle si è reindirizzato automaticamente ad un nuovo container {containerId}.
similar-container-found:
title: Trovato un Container simile
message: >-
Dozzle ha trovato un Container soimile {containerId} in esecuzione sullo stesso Host and verrà automaticamente agganciato ad esso se non premi 'Cancel'.
Dozzle ha trovato un Container simile {containerId} in esecuzione sullo stesso Host e passerà automaticamente ad esso se non premi 'Cancel'.
title:
page-not-found: Pagina non trovata
login: Autenticazione richiesta
dashboard: 1 container | {count} container
settings: Configurazione
settings: Impostazioni
button:
logout: Logout
login: Login
settings: Configurazione
settings: Impostazioni
cancel: Cancel
redirect: Redirect
placeholder:
@@ -73,32 +73,32 @@ placeholder:
search: Cerca
settings:
display: Visualizza
locale: Sovrascrivi Linguaggio
locale: Sovrascrivi Lingua
small-scrollbars: Usa una scrollbars più piccola
show-timesamps: Visualizza timestamp
soft-wrap: Linee morbide
soft-wrap: Soft Wrap
datetime-format: Sovrascrivi data e formato dell'ora
font-size: Grandezza del Font da usare nei log
color-scheme: Schema colori
color-scheme: Tema colori
options: Opzioni
show-stopped-containers: Visualizza i container fermi
show-stopped-containers: Visualizza i container arrestati
about: Circa
search: Abilita la ricerca attraverso Dozzle
using-version: Stai utilizzando Dozzle {version}.
update-available: >-
Nuova versione disponibile! Aggiorna a <a href="{href}" target="_blank" rel="noreferrer noopener">{nextVersion}</a>.
show-std: Visualizza stdout e stderr
automatic-redirect: Automaticamente reindirizza al nuovo container con lo stesso nome
compact: Abilita il compact mode per i log
automatic-redirect: Reindirizza automaticamente al nuovo container con lo stesso nome
compact: Abilita la modalità compatta per i log
log:
preview: This is a preview of the logs
warning: A warning log looks like this
complex: This is a complex log entry as json
simple: This is a very very long message which would wrap by default. Disabling soft wraps would disable this. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
preview: Questa è un'anteprima dei log
warning: Un log di avviso appare così
complex: Questa è un log complesso in formato json
simple: Questo è un messaggio molto molto lungo che dovrebbe andare a capo automaticamente. Disabilitando il soft wrap si può disabilitare questa funzione. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
multi-line-error:
start-line: This is a multi line error message
middle-line: with a second line
end-line: and finally third line.
start-line: Questo è un messaggio di errore su più righe
middle-line: una seconda riga
end-line: e infine una terza riga.
releases:
features: nuova funzione | {count} funzioni
bugFixes: nuovo bug fix | {count} fix
@@ -114,3 +114,9 @@ toasts:
copied:
title: Copiato
message: Log copiato nella clipboard
analytics:
creating_table: Creazione tabella temporanea...
downloading: Recupero dei log dei container... ({size})
evaluating_query: Valutazione della query...
total_records: Totale {count} record.
showing_first: Mostrati i primi {count}.
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: Skopiowany
message: Log skopiowany do schowka
analytics:
creating_table: Tworzenie tymczasowej tabeli...
downloading: Pobieranie logów kontenerów... ({size})
evaluating_query: Przetwarzanie zapytania...
total_records: Razem {count} rekordów.
showing_first: Pokazywanie pierwszych {count}.
+7
View File
@@ -109,3 +109,10 @@ settings:
start-line: Esta é uma mensagem de erro multi-linha
middle-line: com uma segunda linha
end-line: e finalmente uma terceira linha.
analytics:
creating_table: A criar tabela temporária...
downloading: A obter registos dos contentores... ({size})
evaluating_query: A avaliar consulta...
total_records: Total de {count} registos.
showing_first: A mostrar os primeiros {count}.
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: Copiado
message: Log copiado para a área de transferência
analytics:
creating_table: Criando tabela temporária...
downloading: Buscando logs dos containers... ({size})
evaluating_query: Avaliando consulta...
total_records: Total de {count} registros.
showing_first: Mostrando os primeiros {count}.
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: Copied
message: Log copied to clipboard
analytics:
creating_table: Создание временной таблицы...
downloading: Получение логов контейнеров... ({size})
evaluating_query: Выполнение запроса...
total_records: Всего {count} записей.
showing_first: Показаны первые {count}.
+6
View File
@@ -107,3 +107,9 @@ toasts:
copied:
title: Kopyalandı
message: Günlük panoya kopyalandı
analytics:
creating_table: Geçici tablo oluşturuluyor...
downloading: Konteyner günlükleri alınıyor... ({size})
evaluating_query: Sorgu değerlendiriliyor...
total_records: Toplam {count} kayıt.
showing_first: İlk {count} gösteriliyor.
+7 -1
View File
@@ -116,4 +116,10 @@ log_actions:
toasts:
copied:
title: 已複製
message: 日誌已複製到剪貼簿
message: 日誌已複製到剪貼簿
analytics:
creating_table: 正在建立臨時資料表...
downloading: 正在取得容器日誌... ({size})
evaluating_query: 正在評估查詢...
total_records: 共計 {count} 筆記錄。
showing_first: 顯示前 {count} 筆。
+6
View File
@@ -114,3 +114,9 @@ toasts:
copied:
title: 已复制
message: 日志已复制到剪贴板
analytics:
creating_table: 正在创建临时表...
downloading: 正在获取容器日志... ({size})
evaluating_query: 正在评估查询...
total_records: 总共 {count} 条记录。
showing_first: 显示前 {count} 条。
+21 -13
View File
@@ -129,6 +129,14 @@ func main() {
log.Debug().Msg("shut down complete")
}
func fileExists(filename string) bool {
_, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return err == nil
}
func createServer(args cli.Args, hostService web.HostService) *http.Server {
_, dev := os.LookupEnv("DEV")
@@ -141,21 +149,21 @@ func createServer(args cli.Args, hostService web.HostService) *http.Server {
} else if args.AuthProvider == "simple" {
log.Debug().Msg("Using simple authentication")
provider = web.SIMPLE
userFilePath := "./data/users.yml"
if !fileExists(userFilePath) {
userFilePath = "./data/users.yaml"
if !fileExists(userFilePath) {
log.Fatal().Msg("No users.yaml or users.yml file found.")
}
}
path, err := filepath.Abs("./data/users.yml")
if err != nil {
log.Fatal().Err(err).Msg("Could not get absolute path")
}
if _, err := os.Stat(path); os.IsNotExist(err) {
log.Fatal().Msg("users.yml file does not exist")
}
log.Debug().Msgf("Reading %s file", filepath.Base(userFilePath))
log.Debug().Str("path", path).Msg("Reading users.yml file")
db, err := auth.ReadUsersFromFile(path)
if err != nil {
log.Fatal().Err(err).Msg("Could not read users.yml file")
}
db, err := auth.ReadUsersFromFile(userFilePath)
if err != nil {
log.Fatal().Err(err).Msgf("Could not read users file: %s", userFilePath)
}
log.Debug().Int("users", len(db.Users)).Msg("Loaded users")
ttl := time.Duration(0)
+26 -27
View File
@@ -1,12 +1,12 @@
{
"name": "dozzle",
"version": "8.12.4",
"version": "8.12.10",
"description": "Realtime log viewer for docker containers.",
"homepage": "https://github.com/amir20/dozzle#readme",
"bugs": {
"url": "https://github.com/amir20/dozzle/issues"
},
"packageManager": "pnpm@10.7.1",
"packageManager": "pnpm@10.8.1",
"type": "module",
"repository": {
"type": "git",
@@ -29,23 +29,23 @@
"docs:preview": "vitepress preview docs"
},
"dependencies": {
"@duckdb/duckdb-wasm": "1.29.0",
"@duckdb/duckdb-wasm": "1.29.1-dev132.0",
"@iconify-json/carbon": "^1.2.8",
"@iconify-json/cil": "^1.2.2",
"@iconify-json/ic": "^1.2.2",
"@iconify-json/material-symbols": "^1.2.17",
"@iconify-json/material-symbols": "^1.2.20",
"@iconify-json/mdi": "^1.2.3",
"@iconify-json/mdi-light": "^1.2.2",
"@iconify-json/octicon": "^1.2.5",
"@iconify-json/ph": "^1.2.2",
"@intlify/unplugin-vue-i18n": "^6.0.5",
"@oddbird/css-anchor-positioning": "^0.4.0",
"@intlify/unplugin-vue-i18n": "^6.0.7",
"@oddbird/css-anchor-positioning": "^0.5.1",
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/vite": "4.1.2",
"@vueuse/components": "^13.0.0",
"@vueuse/core": "^13.0.0",
"@vueuse/integrations": "^13.0.0",
"@vueuse/router": "^13.0.0",
"@tailwindcss/vite": "4.1.4",
"@vueuse/components": "^13.1.0",
"@vueuse/core": "^13.1.0",
"@vueuse/integrations": "^13.1.0",
"@vueuse/router": "^13.1.0",
"@xterm/addon-web-links": "^0.11.0",
"@xterm/xterm": "^5.5.0",
"ansi-to-html": "^0.7.2",
@@ -55,36 +55,35 @@
"d3-selection": "^3.0.0",
"d3-shape": "^3.2.0",
"d3-transition": "^3.0.1",
"daisyui": "5.0.12",
"daisyui": "5.0.27",
"date-fns": "^4.1.0",
"entities": "^6.0.0",
"fuse.js": "^7.1.0",
"lodash.debounce": "^4.0.8",
"pinia": "^3.0.1",
"pinia": "^3.0.2",
"sortablejs": "^1.15.6",
"splitpanes": "^4.0.3",
"strip-ansi": "^7.1.0",
"tailwindcss": "4.1.2",
"tailwindcss": "4.1.4",
"unplugin-auto-import": "^19.1.2",
"unplugin-icons": "^22.1.0",
"unplugin-vue-components": "^28.4.1",
"unplugin-vue-components": "^28.5.0",
"unplugin-vue-macros": "^2.14.5",
"unplugin-vue-router": "^0.12.0",
"vite": "6.2.5",
"vite-plugin-compression2": "^1.3.3",
"vite": "6.3.2",
"vite-plugin-vue-layouts": "^0.11.0",
"vite-svg-loader": "^5.1.0",
"vitepress": "1.6.3",
"vue": "^3.5.13",
"vue-i18n": "^11.1.2",
"vue-i18n": "^11.1.3",
"vue-router": "^4.5.0"
},
"devDependencies": {
"@apache-arrow/esnext-esm": "^19.0.1",
"@iconify-json/material-symbols-light": "^1.2.17",
"@iconify-json/material-symbols-light": "^1.2.20",
"@iconify-json/ri": "^1.2.5",
"@pinia/testing": "^1.0.0",
"@playwright/test": "^1.51.1",
"@pinia/testing": "^1.0.1",
"@playwright/test": "^1.52.0",
"@types/d3-array": "^3.2.1",
"@types/d3-ease": "^3.0.2",
"@types/d3-scale": "^4.0.9",
@@ -92,7 +91,7 @@
"@types/d3-shape": "^3.1.7",
"@types/d3-transition": "^3.0.9",
"@types/lodash.debounce": "^4.0.9",
"@types/node": "^22.14.0",
"@types/node": "^22.14.1",
"@vitejs/plugin-vue": "5.2.3",
"@vue/compiler-sfc": "^3.5.13",
"@vue/test-utils": "^2.4.6",
@@ -100,16 +99,16 @@
"c8": "^10.1.3",
"concurrently": "^9.1.2",
"eventsourcemock": "^2.0.0",
"jsdom": "^26.0.0",
"lint-staged": "^15.5.0",
"jsdom": "^26.1.0",
"lint-staged": "^15.5.1",
"prettier": "^3.5.3",
"prettier-plugin-tailwindcss": "^0.6.11",
"simple-git-hooks": "^2.12.1",
"ts-node": "^10.9.2",
"typescript": "^5.8.2",
"typescript": "^5.8.3",
"vitest": "^3.1.1",
"vue-component-type-helpers": "3.0.0-alpha.2",
"vue-tsc": "3.0.0-alpha.2"
"vue-component-type-helpers": "3.0.0-alpha.4",
"vue-tsc": "3.0.0-alpha.4"
},
"lint-staged": {
"*.{js,vue,css,ts,html,md}": [
+1174 -1343
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -23,6 +23,9 @@ message Container {
string group = 14;
string command = 15;
google.protobuf.Timestamp finished = 16;
uint64 memoryLimit = 17;
double cpuLimit = 18;
bool fullyLoaded = 19;
}
message ContainerStat {
-2
View File
@@ -9,7 +9,6 @@ import IconsResolver from "unplugin-icons/resolver";
import VueRouter from "unplugin-vue-router/vite";
import Layouts from "vite-plugin-vue-layouts";
import VueI18nPlugin from "@intlify/unplugin-vue-i18n/vite";
import { compression } from "vite-plugin-compression2";
import { VueRouterAutoImports } from "unplugin-vue-router";
import svgLoader from "vite-svg-loader";
import tailwindcss from "@tailwindcss/vite";
@@ -71,7 +70,6 @@ export default defineConfig(() => ({
strictMessage: false,
include: [path.resolve(__dirname, "locales/**")],
}),
compression({ algorithm: "brotliCompress", exclude: [/\.(html)$/] }),
svgLoader({}),
tailwindcss(),
],