Compare commits

...

11 Commits

Author SHA1 Message Date
mbecker20
80a91584a8 version number link to releases 2024-09-07 12:54:54 +03:00
mbecker20
12d05e9a25 1.14.0 stable 2024-09-07 12:51:56 +03:00
mbecker20
f4d06c91ff add 5s log polling option 2024-09-07 12:42:35 +03:00
mbecker20
5d7449529f fix Builder schema link 2024-09-05 01:40:54 +03:00
mbecker20
a0021d1785 obfuscate secret variable value with * 2024-09-04 17:15:59 +03:00
mbecker20
bbd23e3f5f improve login failure feedback 2024-09-04 17:15:47 +03:00
mbecker20
71841a8e41 update komodo CLI readme 2024-09-04 16:48:27 +03:00
mbecker20
5228ffd9b8 fix changelog 2024-09-02 12:54:56 +03:00
mbecker20
a06f506e54 installer log 2024-09-02 03:13:58 +03:00
mbecker20
71d6a55e50 modified installer 2024-09-02 03:12:17 +03:00
mbecker20
d16c03dd2a fix force service file install 2024-09-02 03:09:14 +03:00
13 changed files with 178 additions and 59 deletions

24
Cargo.lock generated
View File

@@ -41,7 +41,7 @@ dependencies = [
[[package]]
name = "alerter"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"axum",
@@ -926,7 +926,7 @@ dependencies = [
[[package]]
name = "command"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"komodo_client",
"run_command",
@@ -1269,7 +1269,7 @@ dependencies = [
[[package]]
name = "formatting"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"serror",
]
@@ -1400,7 +1400,7 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
[[package]]
name = "git"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"command",
@@ -2005,7 +2005,7 @@ dependencies = [
[[package]]
name = "komodo_cli"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"clap",
@@ -2021,7 +2021,7 @@ dependencies = [
[[package]]
name = "komodo_client"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2052,7 +2052,7 @@ dependencies = [
[[package]]
name = "komodo_core"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2107,7 +2107,7 @@ dependencies = [
[[package]]
name = "komodo_periphery"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2182,7 +2182,7 @@ dependencies = [
[[package]]
name = "logger"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"komodo_client",
@@ -2246,7 +2246,7 @@ dependencies = [
[[package]]
name = "migrator"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"dotenvy",
@@ -2771,7 +2771,7 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "periphery_client"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"komodo_client",
@@ -4461,7 +4461,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "update_logger"
version = "1.14.0-rc1"
version = "1.14.0"
dependencies = [
"anyhow",
"komodo_client",

View File

@@ -3,7 +3,7 @@ resolver = "2"
members = ["bin/*", "lib/*", "client/core/rs", "client/periphery/rs"]
[workspace.package]
version = "1.14.0-rc1"
version = "1.14.0"
edition = "2021"
authors = ["mbecker20 <becker.maxh@gmail.com>"]
license = "GPL-3.0-or-later"
@@ -15,7 +15,7 @@ homepage = "https://komo.do"
[workspace.dependencies]
# LOCAL
# komodo_client = "1.14.0-rc1"
# komodo_client = "1.14.0"
komodo_client = { path = "client/core/rs" }
periphery_client = { path = "client/periphery/rs" }
formatting = { path = "lib/formatting" }

View File

@@ -36,41 +36,77 @@ komodo execute run-build test_build
```
#### Manual
`komodo --help`
```md
Command line tool to execute Komodo actions
Usage: komodo [OPTIONS] <COMMAND>
Commands:
execute Runs an execution
help Print this message or the help of the given subcommand(s)
Options:
--creds <CREDS> The path to a creds file [default: /Users/max/.config/komodo/creds.toml]
--url <URL> Pass url in args instead of creds file
--key <KEY> Pass api key in args instead of creds file
--secret <SECRET> Pass api secret in args instead of creds file
-y, --yes Always continue on user confirmation prompts
-h, --help Print help (see more with '--help')
-V, --version Print version
```
`komodo execute --help`
```md
Runs an execution
Usage: komodo execute <COMMAND>
Commands:
none The "null" execution. Does nothing
run-procedure Runs the target procedure. Response: [Update]
run-build Runs the target build. Response: [Update]
cancel-build Cancels the target build. Only does anything if the build is `building` when called. Response: [Update]
deploy Deploys the container for the target deployment. Response: [Update]
start-container Starts the container for the target deployment. Response: [Update]
restart-container Restarts the container for the target deployment. Response: [Update]
pause-container Pauses the container for the target deployment. Response: [Update]
unpause-container Unpauses the container for the target deployment. Response: [Update]
stop-container Stops the container for the target deployment. Response: [Update]
remove-container Stops and removes the container for the target deployment. Reponse: [Update]
clone-repo Clones the target repo. Response: [Update]
pull-repo Pulls the target repo. Response: [Update]
build-repo Builds the target repo, using the attached builder. Response: [Update]
cancel-repo-build Cancels the target repo build. Only does anything if the repo build is `building` when called. Response: [Update]
stop-all-containers Stops all containers on the target server. Response: [Update]
prune-networks Prunes the docker networks on the target server. Response: [Update]
prune-images Prunes the docker images on the target server. Response: [Update]
prune-containers Prunes the docker containers on the target server. Response: [Update]
run-sync Runs the target resource sync. Response: [Update]
deploy-stack Deploys the target stack. `docker compose up`. Response: [Update]
start-stack Starts the target stack. `docker compose start`. Response: [Update]
restart-stack Restarts the target stack. `docker compose restart`. Response: [Update]
pause-stack Pauses the target stack. `docker compose pause`. Response: [Update]
unpause-stack Unpauses the target stack. `docker compose unpause`. Response: [Update]
stop-stack Starts the target stack. `docker compose stop`. Response: [Update]
destroy-stack Destoys the target stack. `docker compose down`. Response: [Update]
sleep
help Print this message or the help of the given subcommand(s)
none The "null" execution. Does nothing
run-procedure Runs the target procedure. Response: [Update]
run-build Runs the target build. Response: [Update]
cancel-build Cancels the target build. Only does anything if the build is `building` when called. Response: [Update]
deploy Deploys the container for the target deployment. Response: [Update]
start-deployment Starts the container for the target deployment. Response: [Update]
restart-deployment Restarts the container for the target deployment. Response: [Update]
pause-deployment Pauses the container for the target deployment. Response: [Update]
unpause-deployment Unpauses the container for the target deployment. Response: [Update]
stop-deployment Stops the container for the target deployment. Response: [Update]
destroy-deployment Stops and destroys the container for the target deployment. Reponse: [Update]
clone-repo Clones the target repo. Response: [Update]
pull-repo Pulls the target repo. Response: [Update]
build-repo Builds the target repo, using the attached builder. Response: [Update]
cancel-repo-build Cancels the target repo build. Only does anything if the repo build is `building` when called. Response: [Update]
start-container Starts the container on the target server. Response: [Update]
restart-container Restarts the container on the target server. Response: [Update]
pause-container Pauses the container on the target server. Response: [Update]
unpause-container Unpauses the container on the target server. Response: [Update]
stop-container Stops the container on the target server. Response: [Update]
destroy-container Stops and destroys the container on the target server. Reponse: [Update]
start-all-containers Starts all containers on the target server. Response: [Update]
restart-all-containers Restarts all containers on the target server. Response: [Update]
pause-all-containers Pauses all containers on the target server. Response: [Update]
unpause-all-containers Unpauses all containers on the target server. Response: [Update]
stop-all-containers Stops all containers on the target server. Response: [Update]
prune-containers Prunes the docker containers on the target server. Response: [Update]
delete-network Delete a docker network. Response: [Update]
prune-networks Prunes the docker networks on the target server. Response: [Update]
delete-image Delete a docker image. Response: [Update]
prune-images Prunes the docker images on the target server. Response: [Update]
delete-volume Delete a docker volume. Response: [Update]
prune-volumes Prunes the docker volumes on the target server. Response: [Update]
prune-system Prunes the docker system on the target server, including volumes. Response: [Update]
run-sync Runs the target resource sync. Response: [Update]
deploy-stack Deploys the target stack. `docker compose up`. Response: [Update]
start-stack Starts the target stack. `docker compose start`. Response: [Update]
restart-stack Restarts the target stack. `docker compose restart`. Response: [Update]
pause-stack Pauses the target stack. `docker compose pause`. Response: [Update]
unpause-stack Unpauses the target stack. `docker compose unpause`. Response: [Update]
stop-stack Starts the target stack. `docker compose stop`. Response: [Update]
destroy-stack Destoys the target stack. `docker compose down`. Response: [Update]
sleep
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help

View File

@@ -4,9 +4,10 @@ use anyhow::anyhow;
use axum::{http::HeaderMap, routing::post, Router};
use axum_extra::{headers::ContentType, TypedHeader};
use komodo_client::{api::auth::*, entities::user::User};
use reqwest::StatusCode;
use resolver_api::{derive::Resolver, Resolve, Resolver};
use serde::{Deserialize, Serialize};
use serror::Json;
use serror::{AddStatusCode, Json};
use typeshare::typeshare;
use uuid::Uuid;
@@ -70,7 +71,10 @@ async fn handler(
}
let elapsed = timer.elapsed();
debug!("/auth request {req_id} | resolve time: {elapsed:?}");
Ok((TypedHeader(ContentType::json()), res?))
Ok((
TypedHeader(ContentType::json()),
res.status_code(StatusCode::UNAUTHORIZED)?,
))
}
fn login_options_reponse() -> &'static GetLoginOptionsResponse {

View File

@@ -1,6 +1,6 @@
# Changelog
## <ins>Komodo v1.13 (Sep 2024)</ins>
## <ins>Komodo v1.14 (Sep 2024)</ins>
- Renamed the project to **Komodo**.
- Manage docker networks, volumes, and images.
- Manage Containers at the server level, without creating any Deployment.

View File

@@ -30,7 +30,7 @@ config.enabled = true # default: false
### Builder and build
- [Builder config schema](https://docs.rs/komodo_client/latest/komodo_client/entities/builder/struct.BuilderConfig.html)
- [Builder config schema](https://docs.rs/komodo_client/latest/komodo_client/entities/builder/enum.BuilderConfig.html)
- [Build config schema](https://docs.rs/komodo_client/latest/komodo_client/entities/build/struct.BuildConfig.html)
```toml

View File

@@ -1,9 +1,9 @@
import { Section } from "@components/layouts";
import { useRead } from "@lib/hooks";
import { useLocalStorage, useRead } from "@lib/hooks";
import { Types } from "@komodo/client";
import { Button } from "@ui/button";
import { RefreshCw, X, AlertOctagon } from "lucide-react";
import { ReactNode, useState } from "react";
import { ReactNode, useEffect, useState } from "react";
import { useDeployment } from ".";
import { Input } from "@ui/input";
import { useToast } from "@ui/use-toast";
@@ -42,6 +42,7 @@ const DeploymentLogsInner = ({
const [terms, setTerms] = useState<string[]>([]);
const [invert, setInvert] = useState(false);
const [search, setSearch] = useState("");
const [poll, setPoll] = useLocalStorage("log-poll-v1", false);
const addTerm = () => {
if (!search.length) return;
@@ -63,6 +64,13 @@ const DeploymentLogsInner = ({
? SearchLogs(id, terms, invert)
: NoSearchLogs(id, tail, stream);
useEffect(() => {
const interval = setInterval(() => {
if (poll) refetch();
}, 5_000);
return () => clearInterval(interval);
}, [poll, refetch]);
return (
<Section
titleOther={titleOther}
@@ -118,6 +126,10 @@ const DeploymentLogsInner = ({
<Button variant="secondary" size="icon" onClick={() => refetch()}>
<RefreshCw className="w-4 h-4" />
</Button>
<div className="flex items-center gap-2">
<div className="text-muted-foreground">Poll</div>
<Switch checked={poll} onCheckedChange={setPoll} />
</div>
<TailLengthSelector
selected={tail}
onSelect={set}

View File

@@ -86,7 +86,7 @@ const Version = () => {
if (!version) return null;
return (
<a
href="https://komo.do"
href="https://github.com/mbecker20/komodo/releases"
target="_blank"
className="hidden lg:block"
>

View File

@@ -15,6 +15,7 @@ import { ThemeToggle } from "@ui/theme";
import { AUTH_TOKEN_STORAGE_KEY, KOMODO_BASE_URL } from "@main";
import { Loader2, X } from "lucide-react";
import { cn } from "@lib/utils";
import { useToast } from "@ui/use-toast";
type OauthProvider = "Github" | "Google";
@@ -62,10 +63,10 @@ const useExchangeToken = () => {
};
export const Login = () => {
// const exchange_token =
const options = useLoginOptions().data;
const [creds, set] = useState({ username: "", password: "" });
const userInvalidate = useUserInvalidate();
const { toast } = useToast();
const onSuccess = ({ jwt }: { jwt: string }) => {
localStorage.setItem(AUTH_TOKEN_STORAGE_KEY, jwt);
userInvalidate();
@@ -74,10 +75,42 @@ export const Login = () => {
"CreateLocalUser",
{
onSuccess,
onError: (e: any) => {
const message = e?.response?.data?.error as string | undefined;
if (message) {
toast({
title: `Failed to login user. '${message}'`,
variant: "destructive",
});
console.error(e);
} else {
toast({
title: "Failed to login user. See console log for details.",
variant: "destructive",
});
console.error(e);
}
},
}
);
const { mutate: login, isPending: loginPending } = useAuth("LoginLocalUser", {
onSuccess,
onError: (e: any) => {
const message = e?.response?.data?.error as string | undefined;
if (message) {
toast({
title: `Failed to login user. '${message}'`,
variant: "destructive",
});
console.error(e);
} else {
toast({
title: "Failed to login user. See console log for details.",
variant: "destructive",
});
console.error(e);
}
},
});
// Handle exchange token loop to avoid showing login flash

View File

@@ -1,6 +1,6 @@
import { Section } from "@components/layouts";
import { Log, TailLengthSelector } from "@components/log";
import { useRead } from "@lib/hooks";
import { useLocalStorage, useRead } from "@lib/hooks";
import { Types } from "@komodo/client";
import { Button } from "@ui/button";
import { Input } from "@ui/input";
@@ -8,7 +8,7 @@ import { Switch } from "@ui/switch";
import { ToggleGroup, ToggleGroupItem } from "@ui/toggle-group";
import { useToast } from "@ui/use-toast";
import { AlertOctagon, RefreshCw, ScrollText, X } from "lucide-react";
import { useState } from "react";
import { useEffect, useState } from "react";
export const ContainerLogs = ({
id,
@@ -24,6 +24,7 @@ export const ContainerLogs = ({
const [terms, setTerms] = useState<string[]>([]);
const [invert, setInvert] = useState(false);
const [search, setSearch] = useState("");
const [poll, setPoll] = useLocalStorage("log-poll-v1", false);
const addTerm = () => {
if (!search.length) return;
@@ -45,6 +46,13 @@ export const ContainerLogs = ({
? SearchLogs(id, container_name, terms, invert)
: NoSearchLogs(id, container_name, tail, stream);
useEffect(() => {
const interval = setInterval(() => {
if (poll) refetch();
}, 5_000);
return () => clearInterval(interval);
}, [poll, refetch]);
return (
<Section
title="Log"
@@ -102,6 +110,10 @@ export const ContainerLogs = ({
<Button variant="secondary" size="icon" onClick={() => refetch()}>
<RefreshCw className="w-4 h-4" />
</Button>
<div className="flex items-center gap-2">
<div className="text-muted-foreground">Poll</div>
<Switch checked={poll} onCheckedChange={setPoll} />
</div>
<TailLengthSelector
selected={tail}
onSelect={set}

View File

@@ -119,6 +119,9 @@ export const Variables = () => {
<SortableHeader column={column} title="Value" />
),
cell: ({ row }) => {
const valueDisplay = row.original.is_secret
? "*".repeat(row.original.value?.length || 0)
: row.original.value;
return (
<div className="flex items-center gap-2">
<Card
@@ -138,7 +141,7 @@ export const Variables = () => {
}}
>
<div className="text-sm text-nowrap overflow-hidden overflow-ellipsis text-muted-foreground w-[200px] xl:w-[240px] 2xl:w-[340px]">
{row.original.value || "Set value"}
{valueDisplay || "Set value"}
</div>
</Card>
<CopyButton content={row.original.value} />

View File

@@ -1,9 +1,9 @@
import { Section } from "@components/layouts";
import { useRead } from "@lib/hooks";
import { useLocalStorage, useRead } from "@lib/hooks";
import { Types } from "@komodo/client";
import { Button } from "@ui/button";
import { RefreshCw, X, AlertOctagon, ScrollText } from "lucide-react";
import { useState } from "react";
import { useEffect, useState } from "react";
import { Input } from "@ui/input";
import { useToast } from "@ui/use-toast";
import { ToggleGroup, ToggleGroupItem } from "@ui/toggle-group";
@@ -44,6 +44,7 @@ const StackLogsInner = ({
const [terms, setTerms] = useState<string[]>([]);
const [invert, setInvert] = useState(false);
const [search, setSearch] = useState("");
const [poll, setPoll] = useLocalStorage("log-poll-v1", false);
const addTerm = () => {
if (!search.length) return;
@@ -65,6 +66,13 @@ const StackLogsInner = ({
? SearchLogs(id, service, terms, invert)
: NoSearchLogs(id, service, tail, stream);
useEffect(() => {
const interval = setInterval(() => {
if (poll) refetch();
}, 5_000);
return () => clearInterval(interval);
}, [poll, refetch]);
return (
<Section
title="Log"
@@ -122,6 +130,10 @@ const StackLogsInner = ({
<Button variant="secondary" size="icon" onClick={() => refetch()}>
<RefreshCw className="w-4 h-4" />
</Button>
<div className="flex items-center gap-2">
<div className="text-muted-foreground">Poll</div>
<Switch checked={poll} onCheckedChange={setPoll} />
</div>
<TailLengthSelector
selected={tail}
onSelect={set}

View File

@@ -90,10 +90,17 @@ def copy_service_file(bin_dir, config_dir, service_dir, user_install):
force_service_recopy = sys.argv.count("--force-service-file") > 0
if force_service_recopy:
print("forcing service file recreation")
# early return is service file already exists
if not force_service_recopy and os.path.isfile(service_file):
print("service file already exists, skipping...")
return
if os.path.isfile(service_file):
if force_service_recopy:
print("deleting existing service file")
os.remove(service_file)
else:
print("service file already exists, skipping...")
return
print(f'creating service file at {service_file}')