Compare commits

..
Author SHA1 Message Date
08e55b5180 2.0.0 (#889)
* modularize openapi structs

* most of execute openapi

* server / stack exec openapi

* most of write openapi

* more write openapi

* add the write openapi definitions

* fmt and bump mogh auth

* gen types

* remove user api, mogh auth handles api keys

* clean up

* cache latest image digests and use this for image update alerting / auto update

* deploy 2.0.0-dev-108

* deploy 2.0.0-dev-109

* add back legacy Action "exec" method calling convention

* typegen

* improve config quick links styling

* improve config styling a bit more

* deploy 2.0.0-dev-110

* finish version upgrades page, and use prism theme oneLight and oneDark

* stack level terminal page

* fix Action import from terminal

* clean up dangling action api keys on startup

* improve swarm service / stack state inference

* deploy 2.0.0-dev-111

* add api docs link

* bump ts types and fix SwarmConfig type name conflict

* use mogh auth for passkey conversion

* align dashboard icon with sidebar

* bump frontend node version

* bump node version in all the dockerfiles

* fix tailwind config module

* fix require to import

* skip auto update for images with pinned digest

* dev 112

* cleanup

* batch check for updates, add check to table multi select actions

* dev-113

* mogh_server = "1.2.0"

* serve static ui index.html with ETag / no-cache

* check update available against all digests for image

* deploy 2.0.0-dev-114

* bump rust to 1.93.0

* bump mogh server and auth

* configure session allow cross site

* deploy 2.0.0-dev-115

* add new config value to example config

* Stack check for update prefers check against deployed service image

* deploy 2.0.0-dev-116

* only send auto updated alert after verifying the deploy was successful

* 2.0.0 UI (#1220)

* new ui using mantine

* resources page

* prog on resource page

* resources and resource layouts

* confirm button and modal

* tweaks

* update details

* topbar updates

* add skeletons for resource implementations

* add resource tables

* add tags to recents cards

* resource page table scrolling

* table component + tags filter

* export toml

* New Resource button

* Fix update details capture closing

* tweaks

* omni search

* refine config

* config tweaks

* implement more configs / resource selector

* add profile page

* provider / account selectors

* container table page

* build config

* deployment config

* fix deployment build version selector

* fix secrets selector

* resource sync config

* mobile topbar and updates

* update details fz sm

* stack config

* terminals page

* create terminal in prog

* create terminal menu

* finish create terminal menu

* terminal pages working

* stack tabs / info

* add executions

* add server header info

* confirm pubkey modal

* improve resource header styling

* FileSource component

* stack service table, move icons.ts

* basic procedure config

* tweak procedure config

* container / image pages

* network / volume pages

* clean up docker resource pages

*  basic log / terminal ui

* reusable log section

* styling

* clean up resource components

* delete in resource header

* log auto select stderr

* fix some bgs

* stack logs with service selector

* stack terminals

* add deployment executions

* use correct icon

* useResource hooks

* build info

* build info

* tweaks

* server tabs

* fix terminal section target

* prog on server tabs

* server stats

* light theme

* start on historical stats

* stack service page

* resource sync tabs

* sync tabs

* more topbar icons

* add settings basic

* add topbar alerts

* tweak stream selector behavior

* tweak alert icon topbar

* improve styling smaller screen

* schedules page and other progress

* onboarding keys

* improve schedule page descriptions

* improve update notifications

* schedule timezone selector

* tag color selector

* finish settings / providers

* use shared-text-update component so settings tables aren't janky

* updates page

* refine updates page

* alert page

* standardize borders

* theme and swarm

* swarm tabs

* swarm node page

* swarm config page

* swarm pages

* swarm task and secret pages

* swarm stack page

* fix stack log service selector in swarm mode

* standard inspect section

* swarm inspect tab

* server and swarm resources tab

* add disable confirm dialog (modal) option for executions

* stack update available indicator

* deployment update available

* add template switch to resource headers

* ResourceHeader + rename

* set editing name onclick

* repo tabs

* server stats table

* refine a bit

* refine deployment / stack header info

* show server stats dashboard. dashboard tables

* action last run in config

* SettingsUsers page

* user page etc

* manage api key

* user base permissions

* color the table multi select

* user group page

* UserAddUserGroup

* active includes deployments / stacks

* improve small screen view

* fix docker pages execution showing

* clean up

* rename frontend to UI

* align profile page styling

* config maintenance windows

* finish maintenance windows

* builder config

* add batch execute dropdown / confirm menu

* batch execute styling

* deploy 2.0.0-dev-117

* improve stats card light theme

* add update page

* improve mobile

* terminal group nowrap

* mobile improvements

* allow unused again

* improve mobile font sizing

* improve mobile updates / alerts

* mobile tabs

* alert page

* add server version mismatch color

* new resource, clearable selector

* Fix build show info tab

* copy resources

* keyboard shortcuts

* server resource header version mismatch

* fix type errors

* container page server multi select

* confirm button clear timeout

* hash compare force uses first 8 for short hash

* fix log height

* copy webhooks

* responsive tweaks

* add icons to server stat sections

* add historical server stats charts

* server stat current card shows usage numbers

* refine current stats more

* fix shortcuts interfering with monaco brave

* clean up unused

* remove v1 frontend

* bump rust version to 1.93.1 and dep versions

* deploy 2.0.0-dev-118

* bump chef rust version

* improve login no auth configured and passkey pending

* Load Average is first historical stat

* procedure / action webhook branch mobile style

* dashboard active styling

* hide actions when none

* Select Template

* execution buttons disabled when loading

* Fix config input issue

* improve tab styling

* rename ConfigSwitch onChange -> onCheckedChange

* ensure section headers consistent spacing

* edit swarm join command

* fix batch executions width

* stack stopped and deployment exited warning instead of critical

* smaller more consistent gaps

* add close button to update / alert details drawer

* stack and deployment state color include update available. Ensure server version mismatch color applied everywhere

* deploy 2.0.0-dev-120

* topbar user dropdown shows user avatar if available

* post link redirect should be to profile

* deploy 2.0.0-dev-121

* improve profile delete styling

* standard api key modal size

* improve login styling

* fix login github / google icon color

* fix some wrapping stuff in tables and tag text disappear

* fix terminal height - same as logs

* single delete terminal

* Update / Alert table filter selector formatted

* tweaks for lg size

* taller data table and blue omnisearch

* refine lg screen size view

* fix sidebar margin right

* "never" -> "Never"

* Add hoverable disk info

* improve disk usage hover card styling

* rename for clarity

* thinner topbar

* config sidebar save

* setters use maps instead of mutations

* notification green contents written success

* fmt

* read request are trace

* deploy 2.0.0-dev-122

* debug level core <> periphery auth identifiers logs

* mogh auth server 1.2.10

* mogh auth 1.2.11

* deploy 2.0.0-dev-123

* Deploy / DeployStack updates invalidate corresponding list query

* confirm action / save modals don't need ConfirmButton

* deploy 2.0.0-dev-124

* proper base64url decode

* fix init admin user

* improve mobile friendly tabs width, and onboardng key copy

* rename resource invalidates

* better maxheight for mobile friendly tabs

* km cli needs to install crypto provider for tls ws

* better responsive confirm save width

* confirm modal better responsiveness

* Fix api key modal too thin

* better api key create

* improve batch execs

* improve tabs

* sidebar more compact

* add missing Repo header Info

* Fix Pull repo

* fix repo Links config

* improve procedure config UI including run stack service

* improve deployment network, restart, termination signal config

* fix confirm update showing entries which have not changed

* example execute terminal uses bash

* Update deployments description

* move build server

* [Docs] Update connect-servers.mdx (#1256)

* Update connect-servers.mdx

* Update connect-servers.mdx

* clean up connect servers

* feat(ci): build (#1018)

* fmt

* fix: more verbose logging (#1017)

* use .with_context for stack run directory canonicalize log

* fix failing doc test

* Improve server resource header hover info

* service selector support swarm stack icon

* fix stack terminals sometimes not disabled when it should be

* add terminal create and delete messages

* bump packages and add Mogh Tech copyright

* revamp docsite

* soften the borders

* clean up stack config

* fix config group header too much gap

* procedure stage menu easier to reach

* deploy 2.0.0-dev-125

* increase universal resource polling

* improve server stats

* fix data table

* down node is critical

* cli add print core info

* add docker swarm feature card

* improve toml resource repetition using macros, and fix Swarm toml support

* swarm config: configure alerting options

* add swarm header info

* Implement New Swarm Config and New Swarm Secret

* brighten tag colors

* continue docs revamp

* fmt

* set more refetch intervals to keep display data fresh

* fix copy not showing copy source when there are no templates

* rename onboarding key fix_existing_servers to privileged

* fix Privileged spelling

* fmt

* more docs improvement

* improve docs intro

* update the curl instructions with easier call method

* fix clippy lints

* refresh the server cache after every server connection successful login

* deploy 2.0.0-dev-126

* add polling to dashboard summary data

* tweak tag opacity

* improve server stat table disk hover

* fix change historical stat length collapse stats

* KOMODO_DISABLE_INIT_RESOURCES

* stack Project Missing should be red

* Fix files on host stacks showing down after reboot until refresh cache

* silence user level write logs SetLastSeenUpdate and PushRecentlyViewed

* See the v2 migration guide

* Improve api logging using more fields

* deploy 2.0.0-dev-127

* cli create api key on database, can use with docker exec into core container

* deploy 2.0.0-dev-128

* advanced km create api-key options

* create onboarding key with cli

* tweak

* onboarding keys use tag name

* deploy 2.0.0-dev-129

* stack procedure stages can select specific services to apply to (default all services)

* docsite dockerfile

* ./docusaurus.config.ts

* need to yarn build

* fix broken link

* improve alert (dropdown) icons

* fix docs sidebar collapse

* add local search functionality

* docs search nice

* homepage features navigate to docs

* only show build cancel when canCancel

* more confirm button confirmprops red

* fix docsite buttons and list more features

* fix sidebar cmd click opens in new tab (is a link)

* execute withBorder

* cleaner execute section

* swap docker compose and deploy containers

* make docs logo align with app

* better mobile button layout

* linked logins / 2fa confirm red styling

* bump rust version to 1.94.0

* move bollard::secret to bollard::config

* deploy 2.0.0-dev-130

* feat: add compose_cmd_wrapper_include for selective command wrapping (#1124)

- Add compose_cmd_wrapper_include field to StackConfig.
- Fix wrapper placeholder text not displaying in MonacoEditor.

* align configuration by removing bold label stuff

* confirm update monaco readonly

* dockerfile binaries / ui images default to :2

* fmt

* refresh server cache lint

* fmt

* disabling send alerts should also disable in UI

* clean up disabled alerting

* deploy 2.0.0-dev-131

* mogh_pki 1.1.3 safer copy from slice

* fix dev container issues on 2.0.0 (#1238)

* fix node version and yarn build in dev container

* ensure keys directories exist and are writable in dev container

* update dev container  image (necessary to fix compiler error)

* fix CORS error in dev container

* more dev container fixes

KOMODO_SESSION_ALLOW_CROSS_SITE: true needed to properly run on Firefox

* fix devcontainer port

* update config pages to use "Webhooks" consistently and fix acronym casing (#1239)

Co-authored-by: Maxwell Becker <49575486+mbecker20@users.noreply.github.com>

* update local dev setup instructions (#1240)

* example mongo deploy dev

* check binary URL (#1116)

* install script improve failed download binary log

* align cli installer with periphery installer

* improve terminal page create experience

* deploy 2.0.0-dev-132

* improve mobile updates with full size query

* fix some internal table wrapping

* fix schedule expression examples

* Add swarm updates / alerts filter

* filter by update available uses location hash instead of localstorage

* sync commit preserve meta "deploy" and "after"

* UI fixes and tweaks

* deploy 2.0.0-dev-133

* add error to warn log

* Stack / deployment should inherit specific Swarm permissions

* Fix inline span formatting (used in logs / errors)

* refactor resource sync pending deploy for better display

* deploy 2.0.0-dev-134

* improve terminal error handling

* deploy 2.0.0-dev-135

* dedicated docs page for v2

* warning about failing to include init: true

* Limit Periphery IPs in Advanced config

* refine setup guide

* 2.0.0

---------

Co-authored-by: Shlee <github@shl.ee>
Co-authored-by: Yujia Qiao <code@rapiz.me>
Co-authored-by: ChanningHe <52875777+ChanningHe@users.noreply.github.com>
Co-authored-by: Steven Loria <sloria1@pm.me>
Co-authored-by: Andreas Brett <andreasbrett@users.noreply.github.com>
2026-03-24 05:50:10 -07:00
349 changed files with 9644 additions and 5694 deletions
+9 -3
View File
@@ -1,6 +1,6 @@
services:
dev:
image: mcr.microsoft.com/devcontainers/rust:1-1-bullseye
image: mcr.microsoft.com/devcontainers/rust:1-bookworm
volumes:
# Mount the root folder that contains .git
- ../:/workspace:cached
@@ -10,13 +10,19 @@ services:
- stacks:/etc/komodo/stacks
command: sleep infinity
ports:
- "9121:9121"
- "9120:9120"
environment:
KOMODO_HOST: http://localhost:9120
KOMODO_FIRST_SERVER: http://localhost:8120
KOMODO_DATABASE_ADDRESS: db
KOMODO_ENABLE_NEW_USERS: true
KOMODO_LOCAL_AUTH: true
KOMODO_JWT_SECRET: a_random_secret
VITE_KOMODO_HOST: http://localhost:9120
KOMODO_CORS_ALLOWED_ORIGINS: http://localhost:5173
KOMODO_CORS_ALLOW_CREDENTIALS: true
PERIPHERY_SSL_ENABLED: false
KOMODO_SESSION_ALLOW_CROSS_SITE: true
links:
- db
# ...
@@ -30,4 +36,4 @@ volumes:
data:
repo-cache:
repos:
stacks:
stacks:
+9 -3
View File
@@ -10,7 +10,7 @@
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "20.12.2"
"version": "22.12.0"
},
"ghcr.io/devcontainers-community/features/deno:1": {
@@ -28,7 +28,8 @@
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
9121
5173,
9120
],
// Use 'postCreateCommand' to run commands after the container is created.
@@ -36,11 +37,16 @@
"runServices": [
"db"
]
],
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
"remoteEnv": {
// Avoid out of memory error when running `yarn build`
"NODE_OPTIONS": "--max-old-space-size=4096"
}
}
+7 -1
View File
@@ -1,3 +1,9 @@
#!/bin/sh
cargo install typeshare-cli
cargo install typeshare-cli
sudo mkdir -p /etc/komodo/keys
sudo chown -R $(whoami) /etc/komodo
sudo mkdir -p /config/keys
sudo chown -R $(whoami) /config
+56
View File
@@ -0,0 +1,56 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
CARGO_TERM_COLOR: always
jobs:
build:
name: Build & Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check
Generated
+153 -124
View File
@@ -82,9 +82,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.21"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -103,9 +103,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "0.2.7"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
dependencies = [
"utf8parse",
]
@@ -138,9 +138,9 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "arc-swap"
version = "1.8.2"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5"
checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6"
dependencies = [
"rustversion",
]
@@ -234,9 +234,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "aws-config"
version = "1.8.14"
version = "1.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a8fc176d53d6fe85017f230405e3255cedb4a02221cb55ed6d76dccbbb099b2"
checksum = "11493b0bad143270fb8ad284a096dd529ba91924c5409adeac856cc1bf047dbc"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -254,7 +254,7 @@ dependencies = [
"fastrand",
"hex",
"http 1.4.0",
"ring",
"sha1",
"time",
"tokio",
"tracing",
@@ -264,9 +264,9 @@ dependencies = [
[[package]]
name = "aws-credential-types"
version = "1.2.13"
version = "1.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d203b0bf2626dcba8665f5cd0871d7c2c0930223d6b6be9097592fea21242d0"
checksum = "8f20799b373a1be121fe3005fba0c2090af9411573878f224df44b42727fcaf7"
dependencies = [
"aws-smithy-async",
"aws-smithy-runtime-api",
@@ -299,9 +299,9 @@ dependencies = [
[[package]]
name = "aws-runtime"
version = "1.7.1"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ede2ddc593e6c8acc6ce3358c28d6677a6dc49b65ba4b37a2befe14a11297e75"
checksum = "5fc0651c57e384202e47153c1260b84a9936e19803d747615edf199dc3b98d17"
dependencies = [
"aws-credential-types",
"aws-sigv4",
@@ -324,9 +324,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ec2"
version = "1.214.0"
version = "1.220.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5011a07318505db9ffe5a03e667653b44ee85d392f0e5f36ebd1fff2f2cbfa8"
checksum = "a4d073e665c1303edc348511ec2509b58a2cee148196f72db33aef5cd47c3573"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -349,9 +349,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sso"
version = "1.95.0"
version = "1.96.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00c5ff27c6ba2cbd95e6e26e2e736676fdf6bcf96495b187733f521cfe4ce448"
checksum = "f64a6eded248c6b453966e915d32aeddb48ea63ad17932682774eb026fbef5b1"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -373,9 +373,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ssooidc"
version = "1.97.0"
version = "1.98.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d186f1e5a3694a188e5a0640b3115ccc6e084d104e16fd6ba968dca072ffef8"
checksum = "db96d720d3c622fcbe08bae1c4b04a72ce6257d8b0584cb5418da00ae20a344f"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -397,9 +397,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sts"
version = "1.99.0"
version = "1.100.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9acba7c62f3d4e2408fa998a3a8caacd8b9a5b5549cf36e2372fbdae329d5449"
checksum = "fafbdda43b93f57f699c5dfe8328db590b967b8a820a13ccdd6687355dfcc7ca"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -422,9 +422,9 @@ dependencies = [
[[package]]
name = "aws-sigv4"
version = "1.4.1"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37411f8e0f4bea0c3ca0958ce7f18f6439db24d555dbd809787262cd00926aa9"
checksum = "b0b660013a6683ab23797778e21f1f854744fdf05f68204b4cca4c8c04b5d1f4"
dependencies = [
"aws-credential-types",
"aws-smithy-http",
@@ -444,9 +444,9 @@ dependencies = [
[[package]]
name = "aws-smithy-async"
version = "1.2.13"
version = "1.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc50d0f63e714784b84223abd7abbc8577de8c35d699e0edd19f0a88a08ae13"
checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc"
dependencies = [
"futures-util",
"pin-project-lite",
@@ -455,9 +455,9 @@ dependencies = [
[[package]]
name = "aws-smithy-http"
version = "0.63.5"
version = "0.63.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d619373d490ad70966994801bc126846afaa0d1ee920697a031f0cf63f2568e7"
checksum = "ba1ab2dc1c2c3749ead27180d333c42f11be8b0e934058fb4b2258ee8dbe5231"
dependencies = [
"aws-smithy-runtime-api",
"aws-smithy-types",
@@ -476,9 +476,9 @@ dependencies = [
[[package]]
name = "aws-smithy-http-client"
version = "1.1.11"
version = "1.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00ccbb08c10f6bcf912f398188e42ee2eab5f1767ce215a02a73bc5df1bbdd95"
checksum = "6a2f165a7feee6f263028b899d0a181987f4fa7179a6411a32a439fba7c5f769"
dependencies = [
"aws-smithy-async",
"aws-smithy-runtime-api",
@@ -506,27 +506,27 @@ dependencies = [
[[package]]
name = "aws-smithy-json"
version = "0.62.4"
version = "0.62.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b3a779093e18cad88bbae08dc4261e1d95018c4c5b9356a52bcae7c0b6e9bb"
checksum = "9648b0bb82a2eedd844052c6ad2a1a822d1f8e3adee5fbf668366717e428856a"
dependencies = [
"aws-smithy-types",
]
[[package]]
name = "aws-smithy-observability"
version = "0.2.5"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d3f39d5bb871aaf461d59144557f16d5927a5248a983a40654d9cf3b9ba183b"
checksum = "a06c2315d173edbf1920da8ba3a7189695827002e4c0fc961973ab1c54abca9c"
dependencies = [
"aws-smithy-runtime-api",
]
[[package]]
name = "aws-smithy-query"
version = "0.60.14"
version = "0.60.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f76a580e3d8f8961e5d48763214025a2af65c2fa4cd1fb7f270a0e107a71b0"
checksum = "1a56d79744fb3edb5d722ef79d86081e121d3b9422cb209eb03aea6aa4f21ebd"
dependencies = [
"aws-smithy-types",
"urlencoding",
@@ -534,9 +534,9 @@ dependencies = [
[[package]]
name = "aws-smithy-runtime"
version = "1.10.2"
version = "1.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ccf7f6eba8b2dcf8ce9b74806c6c185659c311665c4bf8d6e71ebd454db6bf"
checksum = "028999056d2d2fd58a697232f9eec4a643cf73a71cf327690a7edad1d2af2110"
dependencies = [
"aws-smithy-async",
"aws-smithy-http",
@@ -559,9 +559,9 @@ dependencies = [
[[package]]
name = "aws-smithy-runtime-api"
version = "1.11.5"
version = "1.11.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4af6e5def28be846479bbeac55aa4603d6f7986fc5da4601ba324dd5d377516"
checksum = "876ab3c9c29791ba4ba02b780a3049e21ec63dabda09268b175272c3733a79e6"
dependencies = [
"aws-smithy-async",
"aws-smithy-types",
@@ -576,9 +576,9 @@ dependencies = [
[[package]]
name = "aws-smithy-types"
version = "1.4.5"
version = "1.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca2734c16913a45343b37313605d84e7d8b34a4611598ce1d25b35860a2bed3"
checksum = "9d73dbfbaa8e4bc57b9045137680b958d274823509a360abfd8e1d514d40c95c"
dependencies = [
"base64-simd",
"bytes",
@@ -602,18 +602,18 @@ dependencies = [
[[package]]
name = "aws-smithy-xml"
version = "0.60.14"
version = "0.60.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b53543b4b86ed43f051644f704a98c7291b3618b67adf057ee77a366fa52fcaa"
checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3"
dependencies = [
"xmlparser",
]
[[package]]
name = "aws-types"
version = "1.3.13"
version = "1.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0470cc047657c6e286346bdf10a8719d26efd6a91626992e0e64481e44323e96"
checksum = "47c8323699dd9b3c8d5b3c13051ae9cdef58fd179957c882f8374dd8725962d9"
dependencies = [
"aws-credential-types",
"aws-smithy-async",
@@ -653,7 +653,7 @@ dependencies = [
"sha1",
"sync_wrapper",
"tokio",
"tokio-tungstenite",
"tokio-tungstenite 0.28.0",
"tower",
"tower-layer",
"tower-service",
@@ -787,13 +787,13 @@ dependencies = [
[[package]]
name = "bcrypt"
version = "0.18.0"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a0f5948f30df5f43ac29d310b7476793be97c50787e6ef4a63d960a0d0be827"
checksum = "523ab528ce3a7ada6597f8ccf5bd8d85ebe26d5edf311cad4d1d3cfb2d357ac6"
dependencies = [
"base64 0.22.1",
"blowfish",
"getrandom 0.3.4",
"getrandom 0.4.1",
"subtle",
"zeroize",
]
@@ -852,9 +852,9 @@ dependencies = [
[[package]]
name = "bollard"
version = "0.20.1"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "227aa051deec8d16bd9c34605e7aaf153f240e35483dd42f6f78903847934738"
checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4"
dependencies = [
"base64 0.22.1",
"bollard-stubs",
@@ -1064,9 +1064,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.60"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
dependencies = [
"clap_builder",
"clap_derive",
@@ -1074,9 +1074,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.60"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
dependencies = [
"anstream",
"anstyle",
@@ -1086,9 +1086,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.55"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
dependencies = [
"heck",
"proc-macro2",
@@ -1149,7 +1149,7 @@ dependencies = [
[[package]]
name = "command"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"komodo_client",
"shlex",
@@ -1489,7 +1489,7 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
[[package]]
name = "database"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"async-compression",
@@ -1759,7 +1759,7 @@ dependencies = [
[[package]]
name = "encoding"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"bytes",
@@ -1801,7 +1801,7 @@ dependencies = [
[[package]]
name = "environment"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"formatting",
@@ -1930,7 +1930,7 @@ dependencies = [
[[package]]
name = "formatting"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"mogh_error",
]
@@ -2109,7 +2109,7 @@ dependencies = [
[[package]]
name = "git"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"command",
@@ -2709,7 +2709,7 @@ dependencies = [
[[package]]
name = "interpolate"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"komodo_client",
@@ -2835,9 +2835,10 @@ dependencies = [
[[package]]
name = "komodo_cli"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"bcrypt",
"chrono",
"clap",
"colored",
@@ -2852,6 +2853,7 @@ dependencies = [
"mogh_logger",
"mogh_pki",
"mogh_secret_file",
"rustls 0.23.37",
"serde",
"serde_json",
"serde_qs",
@@ -2863,7 +2865,7 @@ dependencies = [
[[package]]
name = "komodo_client"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2892,7 +2894,7 @@ dependencies = [
"strum 0.28.0",
"thiserror 2.0.18",
"tokio",
"tokio-tungstenite",
"tokio-tungstenite 0.29.0",
"tokio-util",
"tracing",
"typeshare",
@@ -2902,7 +2904,7 @@ dependencies = [
[[package]]
name = "komodo_core"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"arc-swap",
@@ -2975,7 +2977,7 @@ dependencies = [
[[package]]
name = "komodo_periphery"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"arc-swap",
@@ -3224,9 +3226,9 @@ dependencies = [
[[package]]
name = "mogh_auth_server"
version = "1.2.6"
version = "1.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0053e21d85b214a3288c50433cf56cd07ac1dacda66201f5e93205810423daec"
checksum = "d649dff8bdacff15df7d65716fcc4e3b1643bbc970d609d31cb45b3e2e02b9ac"
dependencies = [
"anyhow",
"arc-swap",
@@ -3269,9 +3271,9 @@ dependencies = [
[[package]]
name = "mogh_config"
version = "1.0.2"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be34694a34d9b693db2db6b66c3a963c9ee77628b881801e20f110b771acf598"
checksum = "7a75ba6d01ac3bb726f95ee40c9d6b37251a1d538cbaf9ea0945744cfcec4842"
dependencies = [
"colored",
"indexmap 2.13.0",
@@ -3299,9 +3301,9 @@ dependencies = [
[[package]]
name = "mogh_logger"
version = "1.3.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5d0f4b7792da5b8a1786c451d8171fc6a9d7f02d4d59c6529ba353c36774d8d"
checksum = "cc71b30d39325fd768c98f0dc60487365f40eb30f3565f0d986fc2d555f95148"
dependencies = [
"anyhow",
"opentelemetry",
@@ -3315,9 +3317,9 @@ dependencies = [
[[package]]
name = "mogh_pki"
version = "1.1.1"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fcb4cbdee296a86d40a4a133717dbd10fc220e17f0631ec5960bc01f94d36c7"
checksum = "477508d50e1852afd8ed6b546c7cfbc95f6c7c26b9589f9f0f64dd36b5742436"
dependencies = [
"anyhow",
"arc-swap",
@@ -3392,9 +3394,9 @@ dependencies = [
[[package]]
name = "mogh_server"
version = "1.4.4"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3292c49e7483691c6eef791fa96aa2120df97b69241514313e53207945c3d69"
checksum = "66ab833484ee2242003819a2b948421dc3469e7d153db71bd7579d5de2660b81"
dependencies = [
"anyhow",
"axum",
@@ -3683,18 +3685,18 @@ dependencies = [
[[package]]
name = "objc2-core-foundation"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
dependencies = [
"bitflags 2.10.0",
]
[[package]]
name = "objc2-io-kit"
version = "0.3.1"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
dependencies = [
"libc",
"objc2-core-foundation",
@@ -3835,9 +3837,9 @@ dependencies = [
[[package]]
name = "opentelemetry-otlp"
version = "0.31.0"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf"
checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f"
dependencies = [
"http 1.4.0",
"opentelemetry",
@@ -4030,7 +4032,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "periphery_client"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"encoding",
@@ -4082,9 +4084,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.2.16"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pin-utils"
@@ -4227,9 +4229,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.105"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
@@ -4341,9 +4343,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.43"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [
"proc-macro2",
]
@@ -4991,9 +4993,9 @@ dependencies = [
[[package]]
name = "serde_qs"
version = "1.0.0"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac22439301a0b6f45a037681518e3169e8db1db76080e2e9600a08d1027df037"
checksum = "3c742cd44662647326f86b514eadcc227fff4ce684dbbdaf1943f758d5ea058c"
dependencies = [
"itoa",
"percent-encoding",
@@ -5014,9 +5016,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "1.0.4"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
checksum = "876ac351060d4f882bb1032b6369eb0aef79ad9df1ea8bc404874d8cc3d0cd98"
dependencies = [
"serde_core",
]
@@ -5375,9 +5377,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.114"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
@@ -5406,9 +5408,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.38.2"
version = "0.38.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1efc19935b4b66baa6f654ac7924c192f55b175c00a7ab72410fc24284dacda8"
checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f"
dependencies = [
"libc",
"memchr",
@@ -5573,9 +5575,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.49.0"
version = "1.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d"
dependencies = [
"bytes",
"libc",
@@ -5636,6 +5638,18 @@ name = "tokio-tungstenite"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite 0.28.0",
]
[[package]]
name = "tokio-tungstenite"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c"
dependencies = [
"futures-util",
"log",
@@ -5644,7 +5658,7 @@ dependencies = [
"rustls-pki-types",
"tokio",
"tokio-rustls 0.26.4",
"tungstenite",
"tungstenite 0.29.0",
]
[[package]]
@@ -5663,9 +5677,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.11+spec-1.1.0"
version = "1.1.0+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
checksum = "f8195ca05e4eb728f4ba94f3e3291661320af739c4e43779cbdfae82ab239fcc"
dependencies = [
"indexmap 2.13.0",
"serde_core",
@@ -5678,18 +5692,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.7.5+spec-1.1.0"
version = "1.1.0+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
checksum = "97251a7c317e03ad83774a8752a7e81fb6067740609f75ea2b585b569a59198f"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_parser"
version = "1.0.6+spec-1.1.0"
version = "1.1.0+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
checksum = "2334f11ee363607eb04df9b8fc8a13ca1715a72ba8662a26ac285c98aabb4011"
dependencies = [
"winnow",
]
@@ -5708,9 +5722,9 @@ dependencies = [
[[package]]
name = "toml_writer"
version = "1.0.6+spec-1.1.0"
version = "1.1.0+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
checksum = "d282ade6016312faf3e41e57ebbba0c073e4056dab1232ab1cb624199648f8ed"
[[package]]
name = "tonic"
@@ -5753,9 +5767,9 @@ dependencies = [
[[package]]
name = "totp-rs"
version = "5.7.0"
version = "5.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f124352108f58ef88299e909f6e9470f1cdc8d2a1397963901b4a6366206bf72"
checksum = "a2b36a9dd327e9f401320a2cb4572cc76ff43742bcfc3291f871691050f140ba"
dependencies = [
"base32",
"constant_time_eq",
@@ -5966,9 +5980,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.22"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
dependencies = [
"nu-ansi-term",
"serde",
@@ -5983,12 +5997,11 @@ dependencies = [
[[package]]
name = "transport"
version = "2.0.0-dev-120"
version = "2.0.0"
dependencies = [
"anyhow",
"axum",
"bytes",
"colored",
"data-encoding",
"encoding",
"futures-util",
@@ -6002,7 +6015,7 @@ dependencies = [
"sha1",
"sha2",
"tokio",
"tokio-tungstenite",
"tokio-tungstenite 0.29.0",
"tokio-util",
"tracing",
"url",
@@ -6020,6 +6033,23 @@ name = "tungstenite"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442"
dependencies = [
"bytes",
"data-encoding",
"http 1.4.0",
"httparse",
"log",
"rand 0.9.2",
"sha1",
"thiserror 2.0.18",
"utf-8",
]
[[package]]
name = "tungstenite"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8"
dependencies = [
"bytes",
"data-encoding",
@@ -6031,7 +6061,6 @@ dependencies = [
"rustls-pki-types",
"sha1",
"thiserror 2.0.18",
"utf-8",
]
[[package]]
@@ -6235,13 +6264,13 @@ dependencies = [
[[package]]
name = "uuid"
version = "1.21.0"
version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb"
checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37"
dependencies = [
"getrandom 0.4.1",
"js-sys",
"rand 0.9.2",
"rand 0.10.0",
"serde_core",
"wasm-bindgen",
]
@@ -6982,9 +7011,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
version = "0.7.14"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
[[package]]
name = "winreg"
+18 -18
View File
@@ -8,7 +8,7 @@ members = [
]
[workspace.package]
version = "2.0.0-dev-120"
version = "2.0.0"
edition = "2024"
authors = ["mbecker20 <becker.maxh@gmail.com>"]
license = "GPL-3.0-or-later"
@@ -37,33 +37,33 @@ mogh_error = { version = "1.0.3", default-features = false }
derive_default_builder = "0.1.8"
async_timing_util = "1.1.0"
mogh_auth_client = "1.2.2"
mogh_auth_server = "1.2.6"
mogh_auth_server = "1.2.13"
mogh_secret_file = "1.0.1"
mogh_validations = "1.0.1"
mogh_rate_limit = "1.0.1"
partial_derive2 = "0.4.5"
mongo_indexed = "2.0.2"
mogh_resolver = "1.0.0"
mogh_config = "1.0.2"
mogh_logger = "1.3.1"
mogh_server = "1.4.4"
mogh_config = "1.0.4"
mogh_logger = "1.3.2"
mogh_server = "1.4.5"
toml_pretty = "2.0.0"
mogh_cache = "1.1.1"
mogh_pki = "1.1.0"
mogh_pki = "1.1.3"
mungos = "3.2.2"
svi = "1.2.0"
# ASYNC
reqwest = { version = "0.13.2", default-features = false, features = ["json", "stream", "form", "query", "rustls"] }
tokio = { version = "1.49.0", features = ["full"] }
tokio = { version = "1.50.0", features = ["full"] }
tokio-util = { version = "0.7.18", features = ["io", "codec"] }
tokio-stream = { version = "0.1.18", features = ["sync"] }
pin-project-lite = "0.2.16"
pin-project-lite = "0.2.17"
futures-util = "0.3.32"
arc-swap = "1.8.2"
arc-swap = "1.9.0"
# SERVER
tokio-tungstenite = { version = "0.28.0", features = ["rustls-tls-native-roots"] }
tokio-tungstenite = { version = "0.29.0", features = ["rustls-tls-native-roots"] }
axum = { version = "0.8.8", features = ["ws", "json", "macros"] }
axum-extra = { version = "0.12.5", features = ["typed-header"] }
@@ -77,10 +77,10 @@ indexmap = { version = "2.13.0", features = ["serde"] }
serde = { version = "1.0.227", features = ["derive"] }
strum = { version = "0.28.0", features = ["derive"] }
bson = { version = "2.15.0" } # must keep in sync with mongodb version
toml = "0.9.11"
toml = "1.1.0"
serde_yaml_ng = "0.10.0"
serde_json = "1.0.149"
serde_qs = "1.0.0"
serde_qs = "1.1.0"
url = "2.5.8"
# ERROR
@@ -100,7 +100,7 @@ uuid = { version = "1.21.0", features = ["v4", "fast-rng", "serde"] }
rustls = { version = "0.23.37", features = ["aws-lc-rs"] }
data-encoding = "2.10.0"
urlencoding = "2.1.3"
bcrypt = "0.18.0"
bcrypt = "0.19.0"
hmac = "0.12.1"
sha1 = "0.10.6"
sha2 = "0.10.9"
@@ -112,14 +112,14 @@ hickory-resolver = "0.25.2"
portable-pty = "0.9.0"
shell-escape = "0.1.5"
crossterm = "0.29.0"
bollard = "0.20.1"
sysinfo = "0.38.2"
bollard = "0.20.2"
sysinfo = "0.38.4"
shlex = "1.3.0"
# CLOUD
aws-config = "1.8.14"
aws-sdk-ec2 = "1.214.0"
aws-credential-types = "1.2.13"
aws-config = "1.8.15"
aws-sdk-ec2 = "1.220.0"
aws-credential-types = "1.2.14"
## CRON
english-to-cron = "0.1.7"
+1 -1
View File
@@ -1,7 +1,7 @@
## Builds the Komodo Core, Periphery, and Util binaries
## for a specific architecture. Requires OpenSSL 3 or later.
FROM rust:1.93.1-bookworm AS builder
FROM rust:1.94.0-bookworm AS builder
RUN cargo install cargo-strip
WORKDIR /builder
+1 -1
View File
@@ -3,7 +3,7 @@
## Uses chef for dependency caching to help speed up back-to-back builds.
FROM lukemathwalker/cargo-chef:latest-rust-1.93.1-bookworm AS chef
FROM lukemathwalker/cargo-chef:latest-rust-1.94.0-bookworm AS chef
WORKDIR /builder
# Plan just the RECIPE to see if things have changed
+2
View File
@@ -32,7 +32,9 @@ tracing.workspace = true
colored.workspace = true
dotenvy.workspace = true
anyhow.workspace = true
bcrypt.workspace = true
chrono.workspace = true
rustls.workspace = true
tokio.workspace = true
serde.workspace = true
clap.workspace = true
+1 -1
View File
@@ -1,4 +1,4 @@
FROM rust:1.93.1-bullseye AS builder
FROM rust:1.94.0-bullseye AS builder
RUN cargo install cargo-strip
WORKDIR /builder
+1 -1
View File
@@ -1,7 +1,7 @@
## Assumes the latest binaries for x86_64 and aarch64 are already built (by binaries.Dockerfile).
## Since theres no heavy build here, QEMU multi-arch builds are fine for this image.
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:2
ARG X86_64_BINARIES=${BINARIES_IMAGE}-x86_64
ARG AARCH64_BINARIES=${BINARIES_IMAGE}-aarch64
+1 -1
View File
@@ -1,6 +1,6 @@
## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:2
# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries
+13
View File
@@ -0,0 +1,13 @@
use anyhow::Context as _;
use komodo_client::api::read::GetCoreInfo;
pub async fn handle() -> anyhow::Result<()> {
let client = super::komodo_client().await?;
let info = client.read(GetCoreInfo {}).await?;
println!(
"{}",
serde_json::to_string_pretty(&info)
.context("Failed to serialize core info to JSON")?
);
Ok(())
}
+101
View File
@@ -0,0 +1,101 @@
use anyhow::Context as _;
use database::bson::doc;
use komodo_client::{
api::read::FindUser,
entities::{
api_key::ApiKey, config::cli::args::create::CreateApiKey,
komodo_timestamp, random_string,
},
};
use serde_json::json;
use crate::config::cli_config;
pub async fn create(
CreateApiKey {
name,
for_user,
expires,
use_api,
}: &CreateApiKey,
) -> anyhow::Result<()> {
let expires = if let Some(expires_days) = expires {
// now + expires in ms
komodo_timestamp() + expires_days * 24 * 60 * 60 * 1000
} else {
0
};
if *use_api {
// USE API
let client = crate::command::komodo_client().await?;
let keys = if let Some(username) = for_user {
// For service user
let user = client
.read(FindUser {
user: username.to_string(),
})
.await?;
client
.write(
komodo_client::api::write::CreateApiKeyForServiceUser {
user_id: user.id,
name: name.clone().unwrap_or_default(),
expires,
},
)
.await?
} else {
// For self
client
.auth_manage(komodo_client::api::auth::manage::CreateApiKey {
name: name.clone().unwrap_or_default(),
expires: expires as u64,
})
.await?
};
println!(
"{}",
serde_json::to_string_pretty(&keys)
.context("Failed to serialize api keys to JSON")?
);
} else {
// USE DATABASE
let db = database::Client::new(&cli_config().database).await?;
let user = db
.users
.find_one(doc! { "username": for_user })
.await
.context("Failed to query database for user")?
.context("No user found with given username")?;
let key = format!("K_{}_K", random_string(40));
let secret = format!("S_{}_S", random_string(40));
let hashed_secret = bcrypt::hash(&secret, 10)
.context("Failed at hashing secret string")?;
db.api_keys
.insert_one(&ApiKey {
name: name.clone().unwrap_or_default(),
user_id: user.id,
key: key.clone(),
secret: hashed_secret.clone(),
created_at: komodo_timestamp(),
expires,
})
.await?;
println!(
"{}",
serde_json::to_string_pretty(
&json!({ "key": key, "secret": secret })
)
.context("Failed to serialize api keys to JSON")?
);
}
Ok(())
}
+13
View File
@@ -0,0 +1,13 @@
use komodo_client::entities::config::cli::args::create::CreateCommand;
mod api_key;
mod onboarding_key;
pub async fn handle(command: &CreateCommand) -> anyhow::Result<()> {
match command {
CreateCommand::ApiKey(api_key) => api_key::create(api_key).await,
CreateCommand::OnboardingKey(onboarding_key) => {
onboarding_key::create(onboarding_key).await
}
}
}
@@ -0,0 +1,46 @@
use anyhow::Context as _;
use komodo_client::entities::{
config::cli::args::create::CreateOnboardingKey, komodo_timestamp,
};
pub async fn create(
CreateOnboardingKey {
name,
expires,
private_key,
tags,
privileged,
copy_server,
create_builder,
}: &CreateOnboardingKey,
) -> anyhow::Result<()> {
let expires = if let Some(expires_days) = expires {
// now + expires in ms
komodo_timestamp() + expires_days * 24 * 60 * 60 * 1000
} else {
0
};
// USE API
let client = crate::command::komodo_client().await?;
let key = client
.write(komodo_client::api::write::CreateOnboardingKey {
name: name.clone().unwrap_or_default(),
expires,
private_key: private_key.clone(),
tags: tags.clone(),
privileged: *privileged,
copy_server: copy_server.clone().unwrap_or_default(),
create_builder: *create_builder,
})
.await?;
println!(
"{}",
serde_json::to_string_pretty(&key)
.context("Failed to serialize onboarding key to JSON")?
);
Ok(())
}
+2
View File
@@ -15,6 +15,8 @@ use wildcard::Wildcard;
use crate::config::cli_config;
pub mod container;
pub mod core_info;
pub mod create;
pub mod database;
pub mod execute;
pub mod list;
+81 -39
View File
@@ -26,7 +26,7 @@ pub async fn handle_connect(
recreate,
}: &Connect,
) -> anyhow::Result<()> {
handle_terminal_forwarding(async {
handle_terminal_forwarding(server, async {
super::komodo_client()
.await?
.connect_server_terminal(
@@ -56,25 +56,28 @@ pub async fn handle_exec(
}: &Exec,
) -> anyhow::Result<()> {
let server = get_server(server.clone(), container).await?;
handle_terminal_forwarding(async {
super::komodo_client()
.await?
.connect_container_terminal(
server,
container.to_string(),
None,
Some(InitTerminal {
command: Some(shell.to_string()),
recreate: if *recreate {
TerminalRecreateMode::Always
} else {
TerminalRecreateMode::DifferentCommand
},
mode: Some(ContainerTerminalMode::Exec),
}),
)
.await
})
handle_terminal_forwarding(
&format!("{server}/{container}"),
async {
super::komodo_client()
.await?
.connect_container_terminal(
server,
container.to_string(),
None,
Some(InitTerminal {
command: Some(shell.to_string()),
recreate: if *recreate {
TerminalRecreateMode::Always
} else {
TerminalRecreateMode::DifferentCommand
},
mode: Some(ContainerTerminalMode::Exec),
}),
)
.await
},
)
.await
}
@@ -86,25 +89,28 @@ pub async fn handle_attach(
}: &Attach,
) -> anyhow::Result<()> {
let server = get_server(server.clone(), container).await?;
handle_terminal_forwarding(async {
super::komodo_client()
.await?
.connect_container_terminal(
server,
container.to_string(),
None,
Some(InitTerminal {
command: None,
recreate: if *recreate {
TerminalRecreateMode::Always
} else {
TerminalRecreateMode::DifferentCommand
},
mode: Some(ContainerTerminalMode::Attach),
}),
)
.await
})
handle_terminal_forwarding(
&format!("{server}/{container}-attach"),
async {
super::komodo_client()
.await?
.connect_container_terminal(
server,
container.to_string(),
None,
Some(InitTerminal {
command: None,
recreate: if *recreate {
TerminalRecreateMode::Always
} else {
TerminalRecreateMode::DifferentCommand
},
mode: Some(ContainerTerminalMode::Attach),
}),
)
.await
},
)
.await
}
@@ -163,6 +169,7 @@ async fn get_server(
async fn handle_terminal_forwarding<
C: Future<Output = anyhow::Result<TerminalWebsocket>>,
>(
label: &str,
connect: C,
) -> anyhow::Result<()> {
// Need to forward multiple sources into ws write
@@ -247,6 +254,16 @@ async fn handle_terminal_forwarding<
let forward_read = async {
let mut stdout = tokio::io::stdout();
// Write connection message
if let Err(e) = write_connection_message(&mut stdout, label)
.await
.context("Failed to write text to stdout")
{
cancel.cancel();
return Some(e);
}
while let Some(msg) =
future_or_cancel(ws_read.receive_stdout(), &cancel).await
{
@@ -297,6 +314,31 @@ async fn handle_terminal_forwarding<
std::process::exit(0)
}
async fn write_connection_message(
stdout: &mut tokio::io::Stdout,
label: &str,
) -> anyhow::Result<()> {
// Use message without ansi for correct length
let message_clean = format!("# Connected to {label} (km) #");
let bounder = "=".repeat(message_clean.chars().count());
let message = format!(
"# {} to {} {} #",
"Connected".green().bold(),
label.bold(),
"(km)".dimmed()
);
stdout
.write_all(
format!("\n{bounder}\r\n{message}\r\n{bounder}\r\n").as_bytes(),
)
.await?;
let _ = stdout.flush().await;
Ok(())
}
fn resize_message() -> anyhow::Result<TerminalStdinMessage> {
let (cols, rows) = crossterm::terminal::size()
.context("Failed to get terminal size")?;
+7
View File
@@ -12,6 +12,9 @@ mod config;
async fn app() -> anyhow::Result<()> {
dotenvy::dotenv().ok();
rustls::crypto::aws_lc_rs::default_provider()
.install_default()
.expect("Failed to install default crypto provider");
mogh_logger::init(&config::cli_config().cli_logging)?;
let args = config::cli_args();
let env = config::cli_env();
@@ -42,6 +45,7 @@ async fn app() -> anyhow::Result<()> {
}
Ok(())
}
args::Command::CoreInfo => command::core_info::handle().await,
args::Command::Container(container) => {
command::container::handle(container).await
}
@@ -52,6 +56,9 @@ async fn app() -> anyhow::Result<()> {
args::Command::Execute(args) => {
command::execute::handle(&args.execution, args.yes).await
}
args::Command::Create { command } => {
command::create::handle(command).await
}
args::Command::Update { command } => {
command::update::handle(command).await
}
+1 -1
View File
@@ -1,7 +1,7 @@
## All in one, multi stage compile + runtime Docker build for your architecture.
# Build Core
FROM rust:1.93.1-trixie AS core-builder
FROM rust:1.94.0-trixie AS core-builder
RUN cargo install cargo-strip
WORKDIR /builder
+2 -2
View File
@@ -2,8 +2,8 @@
## Sets up the necessary runtime container dependencies for Komodo Core.
## Since theres no heavy build here, QEMU multi-arch builds are fine for this image.
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG UI_IMAGE=ghcr.io/moghtech/komodo-ui:latest
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:2
ARG UI_IMAGE=ghcr.io/moghtech/komodo-ui:2
ARG X86_64_BINARIES=${BINARIES_IMAGE}-x86_64
ARG AARCH64_BINARIES=${BINARIES_IMAGE}-aarch64
+1 -1
View File
@@ -1,7 +1,7 @@
## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).
## Sets up the necessary runtime container dependencies for Komodo Core.
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:2
# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries
+9 -7
View File
@@ -20,7 +20,9 @@ pub async fn send_alert(
let link = resource_link(ResourceTargetVariant::Swarm, id);
match alert.level {
SeverityLevel::Ok => {
format!("{level} | Swarm **{name}** is now **healthy**\n{link}")
format!(
"{level} | Swarm **{name}** is now **healthy**\n{link}"
)
}
SeverityLevel::Critical => {
let err = err
@@ -140,7 +142,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
format!("")
String::new()
};
format!(
"📦 Deployment **{name}** is now **{to}**{target}\nprevious: **{from}**\n{link}"
@@ -161,7 +163,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
format!("")
String::new()
};
format!(
"⬆ Deployment **{name}** has an update available{target}\nimage: **{image}**\n{link}"
@@ -182,7 +184,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
format!("")
String::new()
};
format!(
"⬆ Deployment **{name}** was updated automatically ⏫{target}\nimage: **{image}**\n{link}"
@@ -205,7 +207,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
format!("")
String::new()
};
format!(
"🥞 Stack **{name}** is now {to}{target}\nprevious: **{from}**\n{link}"
@@ -227,7 +229,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
format!("")
String::new()
};
format!(
"⬆ Stack **{name}** has an update available{target}\nservice: **{service}**\nimage: **{image}**\n{link}"
@@ -251,7 +253,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
format!("")
String::new()
};
format!(
"⬆ Stack **{name}** was updated automatically ⏫{target}\n{images_label}: **{images}**\n{link}"
+9 -7
View File
@@ -262,7 +262,9 @@ fn standard_alert_content(alert: &Alert) -> String {
.as_ref()
.map(|e| format!("\nerror: {e}"))
.unwrap_or_default();
format!("{level} | Swarm {name} is unhealthy ❌\n{link}{err}")
format!(
"{level} | Swarm {name} is unhealthy ❌\n{link}{err}"
)
}
_ => unreachable!(),
}
@@ -371,7 +373,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
format!("")
String::new()
};
format!(
"📦Deployment {name} is now {to_state}{target}\nprevious: {from}\n{link}",
@@ -392,7 +394,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
format!("")
String::new()
};
format!(
"⬆ Deployment {name} has an update available{target}\nimage: {image}\n{link}",
@@ -413,7 +415,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
format!("")
String::new()
};
format!(
"⬆ Deployment {name} was updated automatically{target}\nimage: {image}\n{link}",
@@ -436,7 +438,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
format!("")
String::new()
};
format!(
"🥞 Stack {name} is now {to_state}{target}\nprevious: {from}\n{link}",
@@ -458,7 +460,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
format!("")
String::new()
};
format!(
"⬆ Stack {name} has an update available{target}\nservice: {service}\nimage: {image}\n{link}",
@@ -482,7 +484,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
format!("")
String::new()
};
format!(
"⬆ Stack {name} was updated automatically ⏫{target}\n{images_label}: {images_str}\n{link}",
+6 -6
View File
@@ -289,7 +289,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("server: *{server}*\n")
} else {
format!("")
String::new()
};
let blocks = vec![
Block::header(text.clone()),
@@ -317,7 +317,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("server: *{server}*\n")
} else {
format!("")
String::new()
};
let blocks = vec![
Block::header(text.clone()),
@@ -345,7 +345,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("server: *{server}*\n")
} else {
format!("")
String::new()
};
let blocks = vec![
Block::header(text.clone()),
@@ -374,7 +374,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("server: *{server}*\n")
} else {
format!("")
String::new()
};
let blocks = vec![
Block::header(text.clone()),
@@ -402,7 +402,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("server: *{server}*\n")
} else {
format!("")
String::new()
};
let blocks = vec![
Block::header(text.clone()),
@@ -435,7 +435,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("server: *{server}*\n")
} else {
format!("")
String::new()
};
let blocks = vec![
Block::header(text.clone()),
+8 -4
View File
@@ -66,14 +66,14 @@ impl Resolve<ExecuteArgs> for BatchRunAction {
"BatchRunAction",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchRunAction>(&self.pattern, user)
@@ -87,7 +87,7 @@ impl Resolve<ExecuteArgs> for RunAction {
"RunAction",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
action = self.action,
@@ -95,7 +95,11 @@ impl Resolve<ExecuteArgs> for RunAction {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut action = get_check_permissions::<Action>(
&self.action,
+12 -4
View File
@@ -28,7 +28,7 @@ impl Resolve<ExecuteArgs> for TestAlerter {
"TestAlerter",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
alerter = self.alerter,
@@ -36,7 +36,11 @@ impl Resolve<ExecuteArgs> for TestAlerter {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let alerter = get_check_permissions::<Alerter>(
&self.alerter,
@@ -94,7 +98,7 @@ impl Resolve<ExecuteArgs> for SendAlert {
"SendAlert",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
request = format!("{self:?}"),
@@ -102,7 +106,11 @@ impl Resolve<ExecuteArgs> for SendAlert {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let alerters = list_full_for_user::<Alerter>(
Default::default(),
+15 -7
View File
@@ -75,14 +75,14 @@ impl Resolve<ExecuteArgs> for BatchRunBuild {
"BatchRunBuild",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchRunBuild>(&self.pattern, user)
@@ -96,7 +96,7 @@ impl Resolve<ExecuteArgs> for RunBuild {
"RunBuild",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
build = self.build,
@@ -104,7 +104,11 @@ impl Resolve<ExecuteArgs> for RunBuild {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut build = get_check_permissions::<Build>(
&self.build,
@@ -522,7 +526,7 @@ impl Resolve<ExecuteArgs> for CancelBuild {
"CancelBuild",
skip(user, update),
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
build = self.build,
@@ -530,7 +534,11 @@ impl Resolve<ExecuteArgs> for CancelBuild {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let build = get_check_permissions::<Build>(
&self.build,
@@ -626,7 +634,7 @@ async fn handle_post_build_redeploy(build_id: &str) {
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
}
+63 -31
View File
@@ -32,7 +32,7 @@ use crate::{
swarm::swarm_request,
update::update_update,
},
monitor::{update_cache_for_server, update_cache_for_swarm},
monitor::{refresh_server_cache, refresh_swarm_cache},
resource::{self, setup_deployment_execution},
state::action_states,
};
@@ -55,14 +55,14 @@ impl Resolve<ExecuteArgs> for BatchDeploy {
"BatchDeploy",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchDeploy>(&self.pattern, user)
@@ -76,7 +76,7 @@ impl Resolve<ExecuteArgs> for Deploy {
"Deploy",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -86,7 +86,11 @@ impl Resolve<ExecuteArgs> for Deploy {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (mut deployment, swarm_or_server) =
setup_deployment_execution(
@@ -222,7 +226,7 @@ impl Resolve<ExecuteArgs> for Deploy {
.await
{
Ok(logs) => {
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
update.logs.extend(logs)
}
Err(e) => {
@@ -246,7 +250,7 @@ impl Resolve<ExecuteArgs> for Deploy {
.await
{
Ok(log) => {
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.logs.push(log)
}
Err(e) => {
@@ -401,7 +405,7 @@ pub async fn pull_deployment_inner(
Err(e) => Log::error("Pull image", format_serror(&e.into())),
};
update_cache_for_server(server, true).await;
refresh_server_cache(server, true).await;
anyhow::Ok(log)
}
.await;
@@ -418,7 +422,7 @@ impl Resolve<ExecuteArgs> for PullDeployment {
"PullDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -426,7 +430,11 @@ impl Resolve<ExecuteArgs> for PullDeployment {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -472,7 +480,7 @@ impl Resolve<ExecuteArgs> for StartDeployment {
"StartDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -480,7 +488,11 @@ impl Resolve<ExecuteArgs> for StartDeployment {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -527,7 +539,7 @@ impl Resolve<ExecuteArgs> for StartDeployment {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -540,7 +552,7 @@ impl Resolve<ExecuteArgs> for RestartDeployment {
"RestartDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -548,7 +560,11 @@ impl Resolve<ExecuteArgs> for RestartDeployment {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -597,7 +613,7 @@ impl Resolve<ExecuteArgs> for RestartDeployment {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -610,7 +626,7 @@ impl Resolve<ExecuteArgs> for PauseDeployment {
"PauseDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -618,7 +634,11 @@ impl Resolve<ExecuteArgs> for PauseDeployment {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -665,7 +685,7 @@ impl Resolve<ExecuteArgs> for PauseDeployment {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -678,7 +698,7 @@ impl Resolve<ExecuteArgs> for UnpauseDeployment {
"UnpauseDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -686,7 +706,11 @@ impl Resolve<ExecuteArgs> for UnpauseDeployment {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -735,7 +759,7 @@ impl Resolve<ExecuteArgs> for UnpauseDeployment {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -748,7 +772,7 @@ impl Resolve<ExecuteArgs> for StopDeployment {
"StopDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -758,7 +782,11 @@ impl Resolve<ExecuteArgs> for StopDeployment {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -813,7 +841,7 @@ impl Resolve<ExecuteArgs> for StopDeployment {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -837,14 +865,14 @@ impl Resolve<ExecuteArgs> for BatchDestroyDeployment {
"BatchDestroyDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchDestroyDeployment>(
@@ -861,7 +889,7 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
"DestroyDeployment",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -871,7 +899,11 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -910,7 +942,7 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
.await
{
Ok(log) => {
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
log
}
Err(e) => Log::error(
@@ -938,7 +970,7 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
.await
{
Ok(log) => {
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
log
}
Err(e) => Log::error(
+30 -10
View File
@@ -54,14 +54,18 @@ impl Resolve<ExecuteArgs> for ClearRepoCache {
"ClearRepoCache",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id
)
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -133,14 +137,18 @@ impl Resolve<ExecuteArgs> for BackupCoreDatabase {
"BackupCoreDatabase",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
)
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -186,14 +194,18 @@ impl Resolve<ExecuteArgs> for GlobalAutoUpdate {
"GlobalAutoUpdate",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
)
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -368,14 +380,18 @@ impl Resolve<ExecuteArgs> for RotateAllServerKeys {
"RotateAllServerKeys",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
)
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -482,7 +498,7 @@ impl Resolve<ExecuteArgs> for RotateCoreKeys {
"RotateCoreKeys",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
force = self.force,
@@ -490,7 +506,11 @@ impl Resolve<ExecuteArgs> for RotateCoreKeys {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
+51 -21
View File
@@ -49,9 +49,9 @@ mod sync;
use super::Variant;
pub struct ExecuteArgs {
/// The execution id.
/// Unique for every /execute call.
pub id: Uuid,
/// The task id.
/// Unique for every '/execute' call.
pub task_id: Uuid,
pub user: User,
pub update: Update,
}
@@ -60,7 +60,7 @@ pub struct ExecuteArgs {
#[derive(
Serialize, Deserialize, Debug, Clone, Resolve, EnumDiscriminants,
)]
#[strum_discriminants(name(ExecuteRequestVariant), derive(Display))]
#[strum_discriminants(name(ExecuteRequestMethod), derive(Display))]
#[args(ExecuteArgs)]
#[response(JsonString)]
#[error(mogh_error::Error)]
@@ -249,11 +249,19 @@ pub fn inner_handler(
async move {
let log = match handle.await {
Ok(Err(e)) => {
warn!("/execute request {task_id} task error: {e:#}",);
warn!(
api = "Execute",
task_id = task_id.to_string(),
"/execute request task error: {e:#}",
);
Log::error("Task Error", format_serror(&e.into()))
}
Err(e) => {
warn!("/execute request {task_id} spawn error: {e:?}",);
warn!(
api = "Execute",
task_id = task_id.to_string(),
"/execute request spawn error: {e:?}",
);
Log::error("Spawn Error", format!("{e:#?}"))
}
_ => return,
@@ -268,7 +276,7 @@ pub fn inner_handler(
find_one_by_id(&db_client().updates, &update_id)
.await
.context("Failed to query to db")?
.context("No update exists with given id")?;
.context("No Update exists with given id")?;
update.logs.push(log);
update.finalize();
update_update(update).await
@@ -277,7 +285,10 @@ pub fn inner_handler(
if let Err(e) = res {
warn!(
"Failed to update update with task error log | {e:#}"
api = "Execute",
task_id = task_id.to_string(),
update_id,
"Failed to modify Update with task error log | {e:#}"
);
}
}
@@ -293,25 +304,44 @@ async fn task(
user: User,
update: Update,
) -> anyhow::Result<String> {
let variant: ExecuteRequestVariant = (&request).into();
let method: ExecuteRequestMethod = (&request).into();
let user_id = user.id.clone();
let username = user.username.clone();
info!(
"EXECUTE REQUEST {id} | METHOD: {variant} | USER: {} ({})",
user.username, user.id
api = "Execute",
task_id = id.to_string(),
method = method.to_string(),
user_id,
username,
"EXECUTE REQUEST",
);
let res =
match request.resolve(&ExecuteArgs { user, update, id }).await {
Err(e) => Err(e.error),
Ok(JsonString::Err(e)) => Err(
anyhow::Error::from(e)
.context("failed to serialize response"),
),
Ok(JsonString::Ok(res)) => Ok(res),
};
let res = match request
.resolve(&ExecuteArgs {
user,
update,
task_id: id,
})
.await
{
Err(e) => Err(e.error),
Ok(JsonString::Err(e)) => Err(
anyhow::Error::from(e).context("failed to serialize response"),
),
Ok(JsonString::Ok(res)) => Ok(res),
};
if let Err(e) = &res {
warn!("EXECUTE REQUEST {id} | METHOD: {variant} | ERROR: {e:#}");
warn!(
api = "Execute",
task_id = id.to_string(),
method = method.to_string(),
user_id,
username,
"EXECUTE REQUEST | ERROR: {e:#}"
);
}
res
+6 -2
View File
@@ -59,7 +59,7 @@ impl Resolve<ExecuteArgs> for RunProcedure {
"RunProcedure",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
procedure = self.procedure,
@@ -67,7 +67,11 @@ impl Resolve<ExecuteArgs> for RunProcedure {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
Ok(
resolve_inner(self.procedure, user.clone(), update.clone())
+30 -14
View File
@@ -55,14 +55,14 @@ impl Resolve<ExecuteArgs> for BatchCloneRepo {
"BatchCloneRepo",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchCloneRepo>(&self.pattern, user)
@@ -76,7 +76,7 @@ impl Resolve<ExecuteArgs> for CloneRepo {
"CloneRepo",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -84,7 +84,11 @@ impl Resolve<ExecuteArgs> for CloneRepo {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut repo = get_check_permissions::<Repo>(
&self.repo,
@@ -186,14 +190,14 @@ impl Resolve<ExecuteArgs> for BatchPullRepo {
"BatchPullRepo",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchPullRepo>(&self.pattern, user)
@@ -207,7 +211,7 @@ impl Resolve<ExecuteArgs> for PullRepo {
"PullRepo",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -215,7 +219,11 @@ impl Resolve<ExecuteArgs> for PullRepo {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut repo = get_check_permissions::<Repo>(
&self.repo,
@@ -363,14 +371,14 @@ impl Resolve<ExecuteArgs> for BatchBuildRepo {
"BatchBuildRepo",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchBuildRepo>(&self.pattern, user)
@@ -384,7 +392,7 @@ impl Resolve<ExecuteArgs> for BuildRepo {
"BuildRepo",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -392,7 +400,11 @@ impl Resolve<ExecuteArgs> for BuildRepo {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut repo = get_check_permissions::<Repo>(
&self.repo,
@@ -705,7 +717,7 @@ impl Resolve<ExecuteArgs> for CancelRepoBuild {
"CancelRepoBuild",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -713,7 +725,11 @@ impl Resolve<ExecuteArgs> for CancelRepoBuild {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let repo = get_check_permissions::<Repo>(
&self.repo,
+148 -64
View File
@@ -14,7 +14,7 @@ use periphery_client::api;
use crate::{
helpers::{periphery_client, update::update_update},
monitor::update_cache_for_server,
monitor::refresh_server_cache,
permission::get_check_permissions,
state::action_states,
};
@@ -26,7 +26,7 @@ impl Resolve<ExecuteArgs> for StartContainer {
"StartContainer",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -35,7 +35,11 @@ impl Resolve<ExecuteArgs> for StartContainer {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -76,7 +80,7 @@ impl Resolve<ExecuteArgs> for StartContainer {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -90,7 +94,7 @@ impl Resolve<ExecuteArgs> for RestartContainer {
"RestartContainer",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -99,7 +103,11 @@ impl Resolve<ExecuteArgs> for RestartContainer {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -142,7 +150,7 @@ impl Resolve<ExecuteArgs> for RestartContainer {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -156,7 +164,7 @@ impl Resolve<ExecuteArgs> for PauseContainer {
"PauseContainer",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -165,7 +173,11 @@ impl Resolve<ExecuteArgs> for PauseContainer {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -206,7 +218,7 @@ impl Resolve<ExecuteArgs> for PauseContainer {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -220,7 +232,7 @@ impl Resolve<ExecuteArgs> for UnpauseContainer {
"UnpauseContainer",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -229,7 +241,11 @@ impl Resolve<ExecuteArgs> for UnpauseContainer {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -272,7 +288,7 @@ impl Resolve<ExecuteArgs> for UnpauseContainer {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -286,7 +302,7 @@ impl Resolve<ExecuteArgs> for StopContainer {
"StopContainer",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -297,7 +313,11 @@ impl Resolve<ExecuteArgs> for StopContainer {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -340,7 +360,7 @@ impl Resolve<ExecuteArgs> for StopContainer {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -354,7 +374,7 @@ impl Resolve<ExecuteArgs> for DestroyContainer {
"DestroyContainer",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -365,7 +385,11 @@ impl Resolve<ExecuteArgs> for DestroyContainer {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let DestroyContainer {
server,
@@ -416,7 +440,7 @@ impl Resolve<ExecuteArgs> for DestroyContainer {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -430,7 +454,7 @@ impl Resolve<ExecuteArgs> for StartAllContainers {
"StartAllContainers",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -438,7 +462,11 @@ impl Resolve<ExecuteArgs> for StartAllContainers {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -477,7 +505,7 @@ impl Resolve<ExecuteArgs> for StartAllContainers {
);
}
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -490,7 +518,7 @@ impl Resolve<ExecuteArgs> for RestartAllContainers {
"RestartAllContainers",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -498,7 +526,11 @@ impl Resolve<ExecuteArgs> for RestartAllContainers {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -539,7 +571,7 @@ impl Resolve<ExecuteArgs> for RestartAllContainers {
);
}
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -552,7 +584,7 @@ impl Resolve<ExecuteArgs> for PauseAllContainers {
"PauseAllContainers",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -560,7 +592,11 @@ impl Resolve<ExecuteArgs> for PauseAllContainers {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -599,7 +635,7 @@ impl Resolve<ExecuteArgs> for PauseAllContainers {
);
}
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -612,7 +648,7 @@ impl Resolve<ExecuteArgs> for UnpauseAllContainers {
"UnpauseAllContainers",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -620,7 +656,11 @@ impl Resolve<ExecuteArgs> for UnpauseAllContainers {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -661,7 +701,7 @@ impl Resolve<ExecuteArgs> for UnpauseAllContainers {
);
}
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -674,7 +714,7 @@ impl Resolve<ExecuteArgs> for StopAllContainers {
"StopAllContainers",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -682,7 +722,11 @@ impl Resolve<ExecuteArgs> for StopAllContainers {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -721,7 +765,7 @@ impl Resolve<ExecuteArgs> for StopAllContainers {
);
}
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -734,7 +778,7 @@ impl Resolve<ExecuteArgs> for PruneContainers {
"PruneContainers",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -742,7 +786,11 @@ impl Resolve<ExecuteArgs> for PruneContainers {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -785,7 +833,7 @@ impl Resolve<ExecuteArgs> for PruneContainers {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -799,7 +847,7 @@ impl Resolve<ExecuteArgs> for DeleteNetwork {
"DeleteNetwork",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -808,7 +856,11 @@ impl Resolve<ExecuteArgs> for DeleteNetwork {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -846,7 +898,7 @@ impl Resolve<ExecuteArgs> for DeleteNetwork {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -860,7 +912,7 @@ impl Resolve<ExecuteArgs> for PruneNetworks {
"PruneNetworks",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -868,7 +920,11 @@ impl Resolve<ExecuteArgs> for PruneNetworks {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -909,7 +965,7 @@ impl Resolve<ExecuteArgs> for PruneNetworks {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -923,7 +979,7 @@ impl Resolve<ExecuteArgs> for DeleteImage {
"DeleteImage",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -932,7 +988,11 @@ impl Resolve<ExecuteArgs> for DeleteImage {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -967,7 +1027,7 @@ impl Resolve<ExecuteArgs> for DeleteImage {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -981,7 +1041,7 @@ impl Resolve<ExecuteArgs> for PruneImages {
"PruneImages",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -989,7 +1049,11 @@ impl Resolve<ExecuteArgs> for PruneImages {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1028,7 +1092,7 @@ impl Resolve<ExecuteArgs> for PruneImages {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1042,7 +1106,7 @@ impl Resolve<ExecuteArgs> for DeleteVolume {
"DeleteVolume",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1051,7 +1115,11 @@ impl Resolve<ExecuteArgs> for DeleteVolume {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1089,7 +1157,7 @@ impl Resolve<ExecuteArgs> for DeleteVolume {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1103,7 +1171,7 @@ impl Resolve<ExecuteArgs> for PruneVolumes {
"PruneVolumes",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1111,7 +1179,11 @@ impl Resolve<ExecuteArgs> for PruneVolumes {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1150,7 +1222,7 @@ impl Resolve<ExecuteArgs> for PruneVolumes {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1164,7 +1236,7 @@ impl Resolve<ExecuteArgs> for PruneDockerBuilders {
"PruneDockerBuilders",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1172,7 +1244,11 @@ impl Resolve<ExecuteArgs> for PruneDockerBuilders {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1211,7 +1287,7 @@ impl Resolve<ExecuteArgs> for PruneDockerBuilders {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1225,7 +1301,7 @@ impl Resolve<ExecuteArgs> for PruneBuildx {
"PruneBuildx",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1233,7 +1309,11 @@ impl Resolve<ExecuteArgs> for PruneBuildx {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1272,7 +1352,7 @@ impl Resolve<ExecuteArgs> for PruneBuildx {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1286,7 +1366,7 @@ impl Resolve<ExecuteArgs> for PruneSystem {
"PruneSystem",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1294,7 +1374,11 @@ impl Resolve<ExecuteArgs> for PruneSystem {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1332,7 +1416,7 @@ impl Resolve<ExecuteArgs> for PruneSystem {
};
update.logs.push(log);
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
+76 -36
View File
@@ -39,7 +39,7 @@ use crate::{
add_update_without_send, init_execution_update, update_update,
},
},
monitor::{update_cache_for_server, update_cache_for_swarm},
monitor::{refresh_server_cache, refresh_swarm_cache},
permission::get_check_permissions,
resource,
stack::{
@@ -69,14 +69,14 @@ impl Resolve<ExecuteArgs> for BatchDeployStack {
"BatchDeployStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchDeployStack>(&self.pattern, user)
@@ -90,7 +90,7 @@ impl Resolve<ExecuteArgs> for DeployStack {
"DeployStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -100,7 +100,11 @@ impl Resolve<ExecuteArgs> for DeployStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (mut stack, swarm_or_server) = setup_stack_execution(
&self.stack,
@@ -313,10 +317,10 @@ impl Resolve<ExecuteArgs> for DeployStack {
match swarm_or_server {
SwarmOrServer::None => unreachable!(),
SwarmOrServer::Swarm(swarm) => {
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
SwarmOrServer::Server(server) => {
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
}
}
@@ -342,14 +346,14 @@ impl Resolve<ExecuteArgs> for BatchDeployStackIfChanged {
"BatchDeployStackIfChanged",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchDeployStackIfChanged>(
@@ -366,7 +370,7 @@ impl Resolve<ExecuteArgs> for DeployStackIfChanged {
"DeployStackIfChanged",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -375,7 +379,11 @@ impl Resolve<ExecuteArgs> for DeployStackIfChanged {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let stack = get_check_permissions::<Stack>(
&self.stack,
@@ -433,7 +441,7 @@ impl Resolve<ExecuteArgs> for DeployStackIfChanged {
.resolve(&ExecuteArgs {
user: user.clone(),
update,
id: *id,
task_id: *task_id,
})
.await
}
@@ -572,7 +580,7 @@ async fn deploy_services(
.resolve(&ExecuteArgs {
user: user.clone(),
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
}
@@ -603,7 +611,7 @@ async fn restart_services(
.resolve(&ExecuteArgs {
user: user.clone(),
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
}
@@ -766,14 +774,14 @@ impl Resolve<ExecuteArgs> for BatchPullStack {
"BatchPullStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchPullStack>(&self.pattern, user)
@@ -878,7 +886,7 @@ pub async fn pull_stack_inner(
.await?;
// Ensure cached stack state up to date by updating server cache
update_cache_for_server(server, true).await;
refresh_server_cache(server, true).await;
Ok(res)
}
@@ -888,7 +896,7 @@ impl Resolve<ExecuteArgs> for PullStack {
"PullStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -897,7 +905,11 @@ impl Resolve<ExecuteArgs> for PullStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (stack, swarm_or_server) = setup_stack_execution(
&self.stack,
@@ -959,7 +971,7 @@ impl Resolve<ExecuteArgs> for StartStack {
"StartStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -968,7 +980,11 @@ impl Resolve<ExecuteArgs> for StartStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<StartStack>(
&self.stack,
@@ -988,7 +1004,7 @@ impl Resolve<ExecuteArgs> for RestartStack {
"RestartStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -997,7 +1013,11 @@ impl Resolve<ExecuteArgs> for RestartStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<RestartStack>(
&self.stack,
@@ -1019,7 +1039,7 @@ impl Resolve<ExecuteArgs> for PauseStack {
"PauseStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1028,7 +1048,11 @@ impl Resolve<ExecuteArgs> for PauseStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<PauseStack>(
&self.stack,
@@ -1048,7 +1072,7 @@ impl Resolve<ExecuteArgs> for UnpauseStack {
"UnpauseStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1057,7 +1081,11 @@ impl Resolve<ExecuteArgs> for UnpauseStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<UnpauseStack>(
&self.stack,
@@ -1077,7 +1105,7 @@ impl Resolve<ExecuteArgs> for StopStack {
"StopStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1086,7 +1114,11 @@ impl Resolve<ExecuteArgs> for StopStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<StopStack>(
&self.stack,
@@ -1118,14 +1150,14 @@ impl Resolve<ExecuteArgs> for BatchDestroyStack {
"BatchDestroyStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
super::batch_execute::<BatchDestroyStack>(&self.pattern, user)
.await
@@ -1138,7 +1170,7 @@ impl Resolve<ExecuteArgs> for DestroyStack {
"DestroyStack",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1149,7 +1181,11 @@ impl Resolve<ExecuteArgs> for DestroyStack {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (stack, swarm_or_server) = setup_stack_execution(
&self.stack,
@@ -1205,7 +1241,7 @@ impl Resolve<ExecuteArgs> for DestroyStack {
}
// Ensure cached stack state up to date by updating swarm cache
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1233,7 +1269,7 @@ impl Resolve<ExecuteArgs> for RunStackService {
"RunStackService",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1243,7 +1279,11 @@ impl Resolve<ExecuteArgs> for RunStackService {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (mut stack, swarm_or_server) = setup_stack_execution(
&self.stack,
+64 -28
View File
@@ -12,7 +12,7 @@ use mogh_resolver::Resolve;
use crate::{
api::execute::ExecuteArgs,
helpers::{swarm::swarm_request, update::update_update},
monitor::update_cache_for_swarm,
monitor::refresh_swarm_cache,
permission::get_check_permissions,
};
@@ -21,7 +21,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmNodes {
"RemoveSwarmNodes",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -31,7 +31,11 @@ impl Resolve<ExecuteArgs> for RemoveSwarmNodes {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -55,7 +59,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmNodes {
{
Ok(log) => {
update.logs.push(log);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Nodes",
@@ -77,7 +81,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmStacks {
"RemoveSwarmStacks",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -87,7 +91,11 @@ impl Resolve<ExecuteArgs> for RemoveSwarmStacks {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -111,7 +119,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmStacks {
{
Ok(log) => {
update.logs.push(log);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Stacks",
@@ -133,7 +141,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmServices {
"RemoveSwarmServices",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -142,7 +150,11 @@ impl Resolve<ExecuteArgs> for RemoveSwarmServices {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -165,7 +177,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmServices {
{
Ok(log) => {
update.logs.push(log);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Services",
@@ -187,7 +199,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmConfig {
"CreateSwarmConfig",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -196,7 +208,11 @@ impl Resolve<ExecuteArgs> for CreateSwarmConfig {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -222,7 +238,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmConfig {
{
Ok(log) => {
update.logs.push(log);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Create Swarm Config",
@@ -244,7 +260,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmConfig {
"RotateSwarmConfig",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -253,7 +269,11 @@ impl Resolve<ExecuteArgs> for RotateSwarmConfig {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -277,7 +297,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmConfig {
{
Ok(logs) => {
update.logs.extend(logs);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Rotate Swarm Config",
@@ -299,7 +319,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmConfigs {
"RemoveSwarmConfigs",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -308,7 +328,11 @@ impl Resolve<ExecuteArgs> for RemoveSwarmConfigs {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -331,7 +355,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmConfigs {
{
Ok(log) => {
update.logs.push(log);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Configs",
@@ -353,7 +377,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmSecret {
"CreateSwarmSecret",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -362,7 +386,11 @@ impl Resolve<ExecuteArgs> for CreateSwarmSecret {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -389,7 +417,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmSecret {
{
Ok(log) => {
update.logs.push(log);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Create Swarm Secret",
@@ -411,7 +439,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmSecret {
"RotateSwarmSecret",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -420,7 +448,11 @@ impl Resolve<ExecuteArgs> for RotateSwarmSecret {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -444,7 +476,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmSecret {
{
Ok(logs) => {
update.logs.extend(logs);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Rotate Swarm Secret",
@@ -466,7 +498,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmSecrets {
"RemoveSwarmSecrets",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -475,7 +507,11 @@ impl Resolve<ExecuteArgs> for RemoveSwarmSecrets {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -498,7 +534,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmSecrets {
{
Ok(log) => {
update.logs.push(log);
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Secrets",
+79 -182
View File
@@ -21,6 +21,7 @@ use komodo_client::{
repo::Repo,
server::Server,
stack::Stack,
swarm::Swarm,
sync::ResourceSync,
update::{Log, Update},
user::sync_user,
@@ -53,7 +54,7 @@ impl Resolve<ExecuteArgs> for RunSync {
"RunSync",
skip_all,
fields(
id = id.to_string(),
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
sync = self.sync,
@@ -63,7 +64,11 @@ impl Resolve<ExecuteArgs> for RunSync {
)]
async fn resolve(
self,
ExecuteArgs { user, update, id }: &ExecuteArgs,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let RunSync {
sync,
@@ -134,56 +139,36 @@ impl Resolve<ExecuteArgs> for RunSync {
let Some(resource_type) = match_resource_type else {
return Some(name_or_id);
};
match ObjectId::from_str(&name_or_id) {
Ok(_) => match resource_type {
ResourceTargetVariant::Swarm => all_resources
.swarms
.get(&name_or_id)
.map(|s| s.name.clone()),
ResourceTargetVariant::Server => all_resources
.servers
.get(&name_or_id)
.map(|s| s.name.clone()),
ResourceTargetVariant::Stack => all_resources
.stacks
.get(&name_or_id)
.map(|s| s.name.clone()),
ResourceTargetVariant::Deployment => all_resources
.deployments
.get(&name_or_id)
.map(|d| d.name.clone()),
ResourceTargetVariant::Build => all_resources
.builds
.get(&name_or_id)
.map(|b| b.name.clone()),
ResourceTargetVariant::Repo => all_resources
.repos
.get(&name_or_id)
.map(|r| r.name.clone()),
ResourceTargetVariant::Procedure => all_resources
.procedures
.get(&name_or_id)
.map(|p| p.name.clone()),
ResourceTargetVariant::Action => all_resources
.actions
.get(&name_or_id)
.map(|p| p.name.clone()),
ResourceTargetVariant::ResourceSync => all_resources
.syncs
.get(&name_or_id)
.map(|s| s.name.clone()),
ResourceTargetVariant::Builder => all_resources
.builders
.get(&name_or_id)
.map(|b| b.name.clone()),
ResourceTargetVariant::Alerter => all_resources
.alerters
.get(&name_or_id)
.map(|a| a.name.clone()),
ResourceTargetVariant::System => None,
},
Err(_) => Some(name_or_id),
macro_rules! resolve_id_to_name {
($(($Variant:ident, $field:ident)),* $(,)?) => {
match ObjectId::from_str(&name_or_id) {
Ok(_) => match resource_type {
$(
ResourceTargetVariant::$Variant => all_resources
.$field
.get(&name_or_id)
.map(|r| r.name.clone()),
)*
ResourceTargetVariant::System => None,
},
Err(_) => Some(name_or_id),
}
};
}
// New resource types need to be added here manually.
resolve_id_to_name!(
(Server, servers),
(Swarm, swarms),
(Stack, stacks),
(Deployment, deployments),
(Build, builds),
(Repo, repos),
(Procedure, procedures),
(Action, actions),
(ResourceSync, syncs),
(Builder, builders),
(Alerter, alerters),
)
})
.collect::<Vec<_>>()
});
@@ -231,136 +216,39 @@ impl Resolve<ExecuteArgs> for RunSync {
let delete = sync.config.managed || sync.config.delete;
let server_deltas = if sync.config.include_resources {
get_updates_for_execution::<Server>(
resources.servers,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let stack_deltas = if sync.config.include_resources {
get_updates_for_execution::<Stack>(
resources.stacks,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let deployment_deltas = if sync.config.include_resources {
get_updates_for_execution::<Deployment>(
resources.deployments,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let build_deltas = if sync.config.include_resources {
get_updates_for_execution::<Build>(
resources.builds,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let repo_deltas = if sync.config.include_resources {
get_updates_for_execution::<Repo>(
resources.repos,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let procedure_deltas = if sync.config.include_resources {
get_updates_for_execution::<Procedure>(
resources.procedures,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let action_deltas = if sync.config.include_resources {
get_updates_for_execution::<Action>(
resources.actions,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let builder_deltas = if sync.config.include_resources {
get_updates_for_execution::<Builder>(
resources.builders,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let alerter_deltas = if sync.config.include_resources {
get_updates_for_execution::<Alerter>(
resources.alerters,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
let resource_sync_deltas = if sync.config.include_resources {
get_updates_for_execution::<entities::sync::ResourceSync>(
resources.resource_syncs,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
macro_rules! get_deltas {
($(($var:ident, $Type:ident, $field:ident)),* $(,)?) => {
$(
let $var = if sync.config.include_resources {
get_updates_for_execution::<$Type>(
resources.$field,
delete,
match_resource_type,
match_resources.as_deref(),
&id_to_tags,
&sync.config.match_tags,
)
.await?
} else {
Default::default()
};
)*
};
}
// New resource types need to be added here manually.
get_deltas!(
(server_deltas, Server, servers),
(swarm_deltas, Swarm, swarms),
(stack_deltas, Stack, stacks),
(deployment_deltas, Deployment, deployments),
(build_deltas, Build, builds),
(repo_deltas, Repo, repos),
(procedure_deltas, Procedure, procedures),
(action_deltas, Action, actions),
(builder_deltas, Builder, builders),
(alerter_deltas, Alerter, alerters),
(resource_sync_deltas, ResourceSync, resource_syncs),
);
let (
variables_to_create,
@@ -398,6 +286,7 @@ impl Resolve<ExecuteArgs> for RunSync {
if deploy_cache.is_empty()
&& resource_sync_deltas.no_changes()
&& server_deltas.no_changes()
&& swarm_deltas.no_changes()
&& deployment_deltas.no_changes()
&& stack_deltas.no_changes()
&& build_deltas.no_changes()
@@ -425,7 +314,11 @@ impl Resolve<ExecuteArgs> for RunSync {
return Ok(update);
}
// =================
// =====================================================
// The ordering these are executed does matter, since
// latter resources may depend on prior synced resources
// already being updated with the declared state.
// =====================================================
// No deps
maybe_extend(
@@ -464,6 +357,10 @@ impl Resolve<ExecuteArgs> for RunSync {
);
// Dependent on server
maybe_extend(
&mut update.logs,
Swarm::execute_sync_updates(swarm_deltas).await,
);
maybe_extend(
&mut update.logs,
Builder::execute_sync_updates(builder_deltas).await,
+9 -9
View File
@@ -79,7 +79,7 @@ pub async fn handle_build_webhook<B: super::ExtractBranch>(
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -121,7 +121,7 @@ impl RepoExecution for CloneRepo {
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -145,7 +145,7 @@ impl RepoExecution for PullRepo {
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -169,7 +169,7 @@ impl RepoExecution for BuildRepo {
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -272,7 +272,7 @@ impl StackExecution for DeployStack {
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -290,7 +290,7 @@ impl StackExecution for DeployStack {
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -403,7 +403,7 @@ impl SyncExecution for RunSync {
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -517,7 +517,7 @@ pub async fn handle_procedure_webhook<B: super::ExtractBranch>(
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -583,7 +583,7 @@ pub async fn handle_action_webhook<B: super::ExtractBranch>(
.resolve(&ExecuteArgs {
user,
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
+23
View File
@@ -222,8 +222,31 @@ where
.status_code(StatusCode::BAD_REQUEST)?;
P::verify_secret(headers, body, R::custom_secret(&resource))
.status_code(StatusCode::UNAUTHORIZED)?;
info!(
resource_type = R::resource_type().to_string(),
resource_id = id,
source_ip = ip.to_string(),
"Successfully authenticated incoming webhook"
);
debug!(
resource_type = R::resource_type().to_string(),
resource_id = id,
source_ip = ip.to_string(),
"Webhook body: {body}"
);
mogh_error::Result::Ok(resource)
}
.with_failure_rate_limit_using_ip(&GENERAL_RATE_LIMITER, &ip)
.await
.inspect_err(|e| {
warn!(
resource_id = id,
source_ip = ip.to_string(),
"Incoming webhook failed | ERROR: {:#}",
e.error
);
})
}
+17 -7
View File
@@ -70,7 +70,7 @@ pub struct ReadArgs {
#[derive(
Serialize, Deserialize, Debug, Clone, Resolve, EnumDiscriminants,
)]
#[strum_discriminants(name(ReadRequestVariant), derive(Display))]
#[strum_discriminants(name(ReadRequestMethod), derive(Display))]
#[args(ReadArgs)]
#[response(Response)]
#[error(mogh_error::Error)]
@@ -291,18 +291,28 @@ async fn handler(
Json(request): Json<ReadRequest>,
) -> mogh_error::Result<axum::response::Response> {
let req_id = Uuid::new_v4();
let variant: ReadRequestVariant = (&request).into();
let method: ReadRequestMethod = (&request).into();
debug!(
"READ REQUEST {req_id} | METHOD: {variant} | USER: {} ({})",
user.username, user.id
let user_id = user.id.clone();
let username = user.username.clone();
trace!(
req_id = req_id.to_string(),
method = method.to_string(),
user_id,
username,
"READ REQUEST",
);
let res = request.resolve(&ReadArgs { user }).await;
if let Err(e) = &res {
debug!(
"READ REQUEST {req_id} | METHOD: {variant} | ERROR: {:#}",
trace!(
req_id = req_id.to_string(),
method = method.to_string(),
user_id,
username,
"READ REQUEST | ERROR: {:#}",
e.error
);
}
+1 -1
View File
@@ -120,7 +120,7 @@ impl Resolve<ReadArgs> for GetResourceSyncsSummary {
for resource_sync in resource_syncs {
res.total += 1;
if !(resource_sync.info.pending_deploy.to_deploy == 0
if !(resource_sync.info.pending_deploys.is_empty()
&& resource_sync.info.resource_updates.is_empty()
&& resource_sync.info.variable_updates.is_empty()
&& resource_sync.info.user_group_updates.is_empty())
+100 -326
View File
@@ -38,122 +38,45 @@ async fn get_all_targets(
user: &User,
) -> anyhow::Result<Vec<ResourceTarget>> {
let mut targets = Vec::<ResourceTarget>::new();
let all_tags = if tags.is_empty() {
vec![]
} else {
get_all_tags(None).await?
};
targets.extend(
resource::list_full_for_user::<Alerter>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Alerter(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Builder>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Builder(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Server>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Server(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Stack>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Stack(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Deployment>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Deployment(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Build>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Build(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Repo>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Repo(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Procedure>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Procedure(resource.id)),
);
targets.extend(
resource::list_full_for_user::<Action>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::Action(resource.id)),
);
targets.extend(
resource::list_full_for_user::<ResourceSync>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
// These will already be filtered by [ExportResourcesToToml]
.map(|resource| ResourceTarget::ResourceSync(resource.id)),
macro_rules! extend_targets {
($($Type:ident),* $(,)?) => {
$(
targets.extend(
resource::list_full_for_user::<$Type>(
ResourceQuery::builder().tags(tags).build(),
user,
PermissionLevel::Read.into(),
&all_tags,
)
.await?
.into_iter()
.map(|resource| ResourceTarget::$Type(resource.id)),
);
)*
};
}
extend_targets!(
Alerter,
Builder,
Server,
Swarm,
Stack,
Deployment,
Build,
Repo,
Procedure,
Action,
ResourceSync,
);
Ok(targets)
}
@@ -187,6 +110,7 @@ impl Resolve<ReadArgs> for ExportAllResourcesToToml {
targets,
user_groups,
include_variables: self.include_variables,
existing: self.existing,
}
.resolve(args)
.await
@@ -202,131 +126,64 @@ impl Resolve<ReadArgs> for ExportResourcesToToml {
targets,
user_groups,
include_variables,
existing,
} = self;
let mut res = ResourcesToml::default();
let id_to_tags = get_id_to_tags(None).await?;
let ReadArgs { user } = args;
macro_rules! convert_target {
($id:expr, $Type:ident, $field:ident) => {{
let mut resource = get_check_permissions::<$Type>(
&$id,
user,
PermissionLevel::Read.into(),
)
.await?;
$Type::replace_ids(&mut resource);
let (deploy, after) = existing
.as_ref()
.and_then(|e| {
e.$field.iter().find(|r| r.name == resource.name)
})
.map(|r| (r.deploy, r.after.clone()))
.unwrap_or_default();
res.$field.push(convert_resource::<$Type>(
resource,
deploy,
after,
&id_to_tags,
));
}};
}
for target in targets {
match target {
ResourceTarget::Swarm(id) => {
let mut swarm = get_check_permissions::<Swarm>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Swarm::replace_ids(&mut swarm);
res.swarms.push(convert_resource::<Swarm>(
swarm,
false,
vec![],
&id_to_tags,
))
}
ResourceTarget::Server(id) => {
let mut server = get_check_permissions::<Server>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Server::replace_ids(&mut server);
res.servers.push(convert_resource::<Server>(
server,
false,
vec![],
&id_to_tags,
))
convert_target!(id, Server, servers)
}
ResourceTarget::Swarm(id) => {
convert_target!(id, Swarm, swarms)
}
ResourceTarget::Stack(id) => {
let mut stack = get_check_permissions::<Stack>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Stack::replace_ids(&mut stack);
res.stacks.push(convert_resource::<Stack>(
stack,
false,
vec![],
&id_to_tags,
))
convert_target!(id, Stack, stacks)
}
ResourceTarget::Deployment(id) => {
let mut deployment = get_check_permissions::<Deployment>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Deployment::replace_ids(&mut deployment);
res.deployments.push(convert_resource::<Deployment>(
deployment,
false,
vec![],
&id_to_tags,
))
convert_target!(id, Deployment, deployments)
}
ResourceTarget::Build(id) => {
let mut build = get_check_permissions::<Build>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Build::replace_ids(&mut build);
res.builds.push(convert_resource::<Build>(
build,
false,
vec![],
&id_to_tags,
))
}
ResourceTarget::Repo(id) => {
let mut repo = get_check_permissions::<Repo>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Repo::replace_ids(&mut repo);
res.repos.push(convert_resource::<Repo>(
repo,
false,
vec![],
&id_to_tags,
))
convert_target!(id, Build, builds)
}
ResourceTarget::Repo(id) => convert_target!(id, Repo, repos),
ResourceTarget::Procedure(id) => {
let mut procedure = get_check_permissions::<Procedure>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Procedure::replace_ids(&mut procedure);
res.procedures.push(convert_resource::<Procedure>(
procedure,
false,
vec![],
&id_to_tags,
));
convert_target!(id, Procedure, procedures)
}
ResourceTarget::Action(id) => {
let mut action = get_check_permissions::<Action>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Action::replace_ids(&mut action);
res.actions.push(convert_resource::<Action>(
action,
false,
vec![],
&id_to_tags,
));
convert_target!(id, Action, actions)
}
ResourceTarget::Builder(id) => {
convert_target!(id, Builder, builders)
}
ResourceTarget::Alerter(id) => {
convert_target!(id, Alerter, alerters)
}
ResourceTarget::ResourceSync(id) => {
let mut sync = get_check_permissions::<ResourceSync>(
@@ -349,36 +206,6 @@ impl Resolve<ReadArgs> for ExportResourcesToToml {
))
}
}
ResourceTarget::Builder(id) => {
let mut builder = get_check_permissions::<Builder>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Builder::replace_ids(&mut builder);
res.builders.push(convert_resource::<Builder>(
builder,
false,
vec![],
&id_to_tags,
))
}
ResourceTarget::Alerter(id) => {
let mut alerter = get_check_permissions::<Alerter>(
&id,
user,
PermissionLevel::Read.into(),
)
.await?;
Alerter::replace_ids(&mut alerter);
res.alerters.push(convert_resource::<Alerter>(
alerter,
false,
vec![],
&id_to_tags,
))
}
ResourceTarget::System(_) => continue,
};
}
@@ -434,85 +261,32 @@ fn serialize_resources_toml(
) -> anyhow::Result<String> {
let mut toml = String::new();
for server in resources.servers {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[server]]\n");
Server::push_to_toml_string(server, &mut toml)?;
}
for stack in resources.stacks {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[stack]]\n");
Stack::push_to_toml_string(stack, &mut toml)?;
}
for deployment in resources.deployments {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[deployment]]\n");
Deployment::push_to_toml_string(deployment, &mut toml)?;
}
for build in resources.builds {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[build]]\n");
Build::push_to_toml_string(build, &mut toml)?;
}
for repo in resources.repos {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[repo]]\n");
Repo::push_to_toml_string(repo, &mut toml)?;
}
for procedure in resources.procedures {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[procedure]]\n");
Procedure::push_to_toml_string(procedure, &mut toml)?;
}
for action in resources.actions {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[action]]\n");
Action::push_to_toml_string(action, &mut toml)?;
}
for alerter in resources.alerters {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[alerter]]\n");
Alerter::push_to_toml_string(alerter, &mut toml)?;
}
for builder in resources.builders {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[builder]]\n");
Builder::push_to_toml_string(builder, &mut toml)?;
}
for resource_sync in resources.resource_syncs {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str("[[resource_sync]]\n");
ResourceSync::push_to_toml_string(resource_sync, &mut toml)?;
macro_rules! serialize_resources {
($(($Type:ident, $field:ident, $header:literal)),* $(,)?) => {
$(
for resource in resources.$field {
if !toml.is_empty() {
toml.push_str("\n\n##\n\n");
}
toml.push_str(concat!("[[",$header,"]]\n"));
$Type::push_to_toml_string(resource, &mut toml)?;
}
)*
};
}
serialize_resources!(
(Server, servers, "server"),
(Swarm, swarms, "swarm"),
(Stack, stacks, "stack"),
(Deployment, deployments, "deployment"),
(Build, builds, "build"),
(Repo, repos, "repo"),
(Procedure, procedures, "procedure"),
(Action, actions, "action"),
(Alerter, alerters, "alerter"),
(Builder, builders, "builder"),
(ResourceSync, resource_syncs, "resource_sync"),
);
for variable in &resources.variables {
if !toml.is_empty() {
+12 -1
View File
@@ -71,9 +71,20 @@ impl Resolve<ReadArgs> for ListUsers {
anyhow!("this route is only accessable by admins").into(),
);
}
let filter = match self.service_users {
komodo_client::api::read::ServiceUserQueryBehavior::Include => {
None
}
komodo_client::api::read::ServiceUserQueryBehavior::Exclude => {
Some(doc! { "config.type": { "$ne": "Service" } })
}
komodo_client::api::read::ServiceUserQueryBehavior::Only => {
Some(doc! { "config.type": "Service" })
}
};
let mut users = find_collect(
&db_client().users,
None,
filter,
FindOptions::builder().sort(doc! { "username": 1 }).build(),
)
.await
+2 -2
View File
@@ -436,7 +436,7 @@ pub async fn check_deployment_for_update_inner(
update_available: false,
});
}
let domain = extract_registry_domain(&image)?;
let domain = extract_registry_domain(image)?;
let account =
optional_string(&deployment.config.image_registry_account);
let token = if let Some(account) = &account {
@@ -458,7 +458,7 @@ pub async fn check_deployment_for_update_inner(
};
let latest_digest = image_digest_cache()
.get(&swarm_or_server, &image, account, token)
.get(swarm_or_server, image, account, token)
.await?;
resource::update_info::<Deployment>(
+24 -8
View File
@@ -54,7 +54,7 @@ pub struct WriteArgs {
#[derive(
Serialize, Deserialize, Debug, Clone, Resolve, EnumDiscriminants,
)]
#[strum_discriminants(name(WriteRequestVariant), derive(Display))]
#[strum_discriminants(name(WriteRequestMethod), derive(Display))]
#[args(WriteArgs)]
#[response(Response)]
#[error(mogh_error::Error)]
@@ -255,19 +255,35 @@ async fn task(
request: WriteRequest,
user: User,
) -> mogh_error::Result<axum::response::Response> {
let req_id = Uuid::new_v4();
let variant: WriteRequestVariant = (&request).into();
let task_id = Uuid::new_v4();
let method: WriteRequestMethod = (&request).into();
info!(
"WRITE REQUEST {req_id} | METHOD: {variant} | USER: {} ({})",
user.username, user.id
);
let user_id = user.id.clone();
let username = user.username.clone();
if !matches!(
request,
WriteRequest::SetLastSeenUpdate(_)
| WriteRequest::PushRecentlyViewed(_)
) {
info!(
task_id = task_id.to_string(),
method = method.to_string(),
user_id,
username,
"WRITE REQUEST",
);
}
let res = request.resolve(&WriteArgs { user }).await;
if let Err(e) = &res {
warn!(
"WRITE REQUEST {req_id} | METHOD: {variant} | ERROR: {:#}",
task_id = task_id.to_string(),
method = method.to_string(),
user_id,
username,
"WRITE REQUEST | ERROR: {:#}",
e.error
);
}
+38 -5
View File
@@ -15,7 +15,10 @@ use mogh_pki::EncodedKeyPair;
use mogh_resolver::Resolve;
use reqwest::StatusCode;
use crate::{api::write::WriteArgs, state::db_client};
use crate::{
api::write::WriteArgs, helpers::query::get_all_tags,
state::db_client,
};
//
@@ -53,6 +56,21 @@ impl Resolve<WriteArgs> for CreateOnboardingKey {
)?
.public
.into_inner();
let tags = if self.tags.is_empty() {
self.tags
} else {
// fix_tags by ensuring existence, and force replace with tag name.
let all_tags = get_all_tags(None).await?;
self
.tags
.into_iter()
.filter_map(|tag| {
let tag =
all_tags.iter().find(|t| t.id == tag || t.name == tag)?;
Some(tag.name.clone())
})
.collect()
};
let onboarding_key = OnboardingKey {
public_key,
name: self.name,
@@ -60,8 +78,8 @@ impl Resolve<WriteArgs> for CreateOnboardingKey {
onboarded: Default::default(),
created_at: komodo_timestamp(),
expires: self.expires,
tags: self.tags,
fix_existing_servers: self.fix_existing_servers,
tags,
privileged: self.privileged,
copy_server: self.copy_server,
create_builder: self.create_builder,
};
@@ -139,11 +157,26 @@ impl Resolve<WriteArgs> for UpdateOnboardingKey {
}
if let Some(tags) = self.tags {
let tags = if tags.is_empty() {
tags
} else {
// fix_tags by ensuring existence, and force replace with tag name.
let all_tags = get_all_tags(None).await?;
tags
.into_iter()
.filter_map(|tag| {
let tag = all_tags
.iter()
.find(|t| t.id == tag || t.name == tag)?;
Some(tag.name.clone())
})
.collect()
};
update.insert("tags", tags);
}
if let Some(fix_existing_servers) = self.fix_existing_servers {
update.insert("fix_existing_servers", fix_existing_servers);
if let Some(privileged) = self.privileged {
update.insert("privileged", privileged);
}
if let Some(copy_server) = self.copy_server {
+12 -3
View File
@@ -563,7 +563,16 @@ impl Resolve<WriteArgs> for RefreshStackCache {
(services, Some(contents), Some(errors), None, None)
} else {
(vec![], None, None, None, None)
// This path is reached if the swarm / server is not available.
// It carries over the last successful poll.
(
stack.info.latest_services,
stack.info.remote_contents,
stack.info.remote_errors,
// Files on host can set hash / message back to None.
None,
None,
)
}
} else if !repo_empty {
// ================
@@ -771,7 +780,7 @@ pub async fn check_stack_for_update_inner(
service.image_digest = None;
continue;
}
match cache.get(&swarm_or_server, image, None, None).await {
match cache.get(swarm_or_server, image, None, None).await {
Ok(digest) => service.image_digest = Some(digest),
Err(e) => {
warn!(
@@ -861,7 +870,7 @@ pub async fn check_stack_for_update_inner(
};
service_with_update.update_available =
latest_digest.update_available(&current_digests);
latest_digest.update_available(current_digests);
if service_with_update.update_available
&& (skip_auto_update || !stack.config.auto_update)
+46 -105
View File
@@ -26,7 +26,8 @@ use komodo_client::{
repo::Repo,
server::Server,
stack::Stack,
sync::{ResourceSync, ResourceSyncInfo, SyncDeployUpdate},
swarm::Swarm,
sync::{ResourceSync, ResourceSyncInfo},
to_path_compatible_name,
update::{Log, Update},
user::sync_user,
@@ -515,11 +516,20 @@ impl Resolve<WriteArgs> for CommitSync {
None
};
// Get the latest existing resources to preserve any meta values
let RemoteResources { resources, .. } =
crate::sync::remote::get_remote_resources(&sync, repo.as_ref())
.await
.context("failed to get remote resources")?;
let res = ExportAllResourcesToToml {
include_resources: sync.config.include_resources,
tags: sync.config.match_tags.clone(),
include_variables: sync.config.include_variables,
include_user_groups: sync.config.include_user_groups,
existing: resources
.inspect_err(|e| warn!("Existing resource TOML is unavailable, resource meta will not be preserved | ERROR: {e:#}"))
.ok(),
}
.resolve(&ReadArgs {
user: sync_user().to_owned(),
@@ -775,110 +785,40 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
let mut diffs = Vec::new();
push_updates_for_view::<Server>(
resources.servers,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Stack>(
resources.stacks,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Deployment>(
resources.deployments,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Build>(
resources.builds,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Repo>(
resources.repos,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Procedure>(
resources.procedures,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Action>(
resources.actions,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Builder>(
resources.builders,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<Alerter>(
resources.alerters,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
push_updates_for_view::<ResourceSync>(
resources.resource_syncs,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
macro_rules! push_updates {
($(($Type:ident, $field:ident)),* $(,)?) => {
$(
push_updates_for_view::<$Type>(
resources.$field,
delete,
None,
None,
&id_to_tags,
&sync.config.match_tags,
&mut diffs,
)
.await?;
)*
};
}
// New resource types need to be added here manually.
push_updates!(
(Server, servers),
(Swarm, swarms),
(Stack, stacks),
(Deployment, deployments),
(Build, builds),
(Repo, repos),
(Procedure, procedures),
(Action, actions),
(Builder, builders),
(Alerter, alerters),
(ResourceSync, resource_syncs),
);
(diffs, deploy_updates)
} else {
(Vec::new(), SyncDeployUpdate::default())
Default::default()
};
let variable_updates = if sync.config.include_variables {
@@ -912,7 +852,7 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
let (
resource_updates,
deploy_updates,
(pending_deploys, pending_deploy_error),
variable_updates,
user_group_updates,
pending_error,
@@ -928,7 +868,7 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
};
let has_updates = !resource_updates.is_empty()
|| !deploy_updates.to_deploy == 0
|| !pending_deploys.is_empty()
|| !variable_updates.is_empty()
|| !user_group_updates.is_empty();
@@ -940,7 +880,8 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
remote_errors: sync.info.remote_errors,
pending_hash: sync.info.pending_hash,
pending_message: sync.info.pending_message,
pending_deploy: deploy_updates,
pending_deploys,
pending_deploy_error,
resource_updates,
variable_updates,
user_group_updates,
+29 -15
View File
@@ -3,8 +3,12 @@ use futures_util::{StreamExt as _, stream::FuturesUnordered};
use komodo_client::{
api::write::*,
entities::{
NoData, deployment::Deployment, permission::PermissionLevel,
server::Server, stack::Stack, terminal::TerminalTarget,
NoData,
deployment::Deployment,
permission::PermissionLevel,
server::Server,
stack::Stack,
terminal::{Terminal, TerminalTarget},
user::User,
},
};
@@ -47,30 +51,35 @@ impl Resolve<WriteArgs> for CreateTerminal {
async fn resolve(
self,
WriteArgs { user }: &WriteArgs,
) -> mogh_error::Result<NoData> {
) -> mogh_error::Result<Terminal> {
match self.target.clone() {
TerminalTarget::Server { server } => {
let server = server
.context("Must provide 'target.params.server'")
.status_code(StatusCode::BAD_REQUEST)?;
create_server_terminal(self, server, user).await?;
create_server_terminal(self, server, user)
.await
.map_err(Into::into)
}
TerminalTarget::Container { server, container } => {
create_container_terminal(self, server, container, user)
.await?;
.await
.map_err(Into::into)
}
TerminalTarget::Stack { stack, service } => {
let service = service
.context("Must provide 'target.params.service'")
.status_code(StatusCode::BAD_REQUEST)?;
create_stack_service_terminal(self, stack, service, user)
.await?;
.await
.map_err(Into::into)
}
TerminalTarget::Deployment { deployment } => {
create_deployment_terminal(self, deployment, user).await?;
create_deployment_terminal(self, deployment, user)
.await
.map_err(Into::into)
}
};
Ok(NoData {})
}
}
}
@@ -84,7 +93,7 @@ async fn create_server_terminal(
}: CreateTerminal,
server: String,
user: &User,
) -> anyhow::Result<()> {
) -> anyhow::Result<Terminal> {
let server = get_check_permissions::<Server>(
&server,
user,
@@ -94,7 +103,7 @@ async fn create_server_terminal(
let periphery = periphery_client(&server).await?;
periphery
let mut terminal = periphery
.request(api::terminal::CreateServerTerminal {
name,
command,
@@ -103,7 +112,12 @@ async fn create_server_terminal(
.await
.context("Failed to create Server Terminal on Periphery")?;
Ok(())
// Fix server terminal target with server id
terminal.target = TerminalTarget::Server {
server: Some(server.id),
};
Ok(terminal)
}
async fn create_container_terminal(
@@ -111,7 +125,7 @@ async fn create_container_terminal(
server: String,
container: String,
user: &User,
) -> anyhow::Result<()> {
) -> anyhow::Result<Terminal> {
let server = get_check_permissions::<Server>(
&server,
user,
@@ -127,7 +141,7 @@ async fn create_stack_service_terminal(
stack: String,
service: String,
user: &User,
) -> anyhow::Result<()> {
) -> anyhow::Result<Terminal> {
let (_, periphery, container) =
get_stack_service_periphery_container(&stack, &service, user)
.await?;
@@ -138,7 +152,7 @@ async fn create_deployment_terminal(
req: CreateTerminal,
deployment: String,
user: &User,
) -> anyhow::Result<()> {
) -> anyhow::Result<Terminal> {
let (_, periphery, container) =
get_deployment_periphery_container(&deployment, user).await?;
create_container_terminal_inner(req, &periphery, container).await
+15
View File
@@ -36,6 +36,15 @@ use super::WriteArgs;
const RECENTLY_VIEWED_MAX: usize = 10;
impl Resolve<WriteArgs> for PushRecentlyViewed {
#[instrument(
"PushRecentlyViewed",
level = "debug",
skip_all,
fields(
user_id = user.id,
resource = format!("{:?}", self.resource)
)
)]
async fn resolve(
self,
WriteArgs { user, .. }: &WriteArgs,
@@ -79,6 +88,12 @@ impl Resolve<WriteArgs> for PushRecentlyViewed {
//
impl Resolve<WriteArgs> for SetLastSeenUpdate {
#[instrument(
"SetLastSeenUpdate",
level = "debug",
skip_all,
fields(user_id = user.id)
)]
async fn resolve(
self,
WriteArgs { user, .. }: &WriteArgs,
+18 -5
View File
@@ -5,6 +5,7 @@ use axum::{
response::IntoResponse,
};
use bytes::Bytes;
use colored::Colorize;
use futures_util::{SinkExt, StreamExt as _};
use komodo_client::{
api::terminal::ConnectTerminalQuery, entities::user::User,
@@ -128,14 +129,26 @@ async fn forward_ws_channel(
};
}
Ok(Err(e)) => {
let _ = client_send
.send(ws::Message::text(format!("{e:#}")))
.await;
let message = format!("{}: {e:#}", "ERROR".red().bold());
if message.contains("pty exited") {
let _ = client_send
.send(ws::Message::text(format!(
"\n{} {}",
"pty".bold(),
"exited".red().bold()
)))
.await;
} else {
let _ = client_send
.send(ws::Message::text(message.replace('\n', "\r\n")))
.await;
}
break;
}
Err(_) => {
let _ =
client_send.send(ws::Message::text("STREAM EOF")).await;
let _ = client_send
.send(ws::Message::text("\r\n\nSTREAM EOF"))
.await;
break;
}
}
+1 -1
View File
@@ -148,7 +148,7 @@ impl AuthImpl for KomodoAuthImpl {
fn post_link_redirect(&self) -> &str {
static POST_LINK_REDIRECT: LazyLock<String> =
LazyLock::new(|| format!("{}/settings", core_config().host));
LazyLock::new(|| format!("{}/profile", core_config().host));
&POST_LINK_REDIRECT
}
+1 -3
View File
@@ -403,9 +403,7 @@ pub fn core_config() -> &'static CoreConfig {
ssl_cert_file: env
.komodo_ssl_cert_file
.unwrap_or(config.ssl_cert_file),
ui_path: env
.komodo_ui_path
.unwrap_or(config.ui_path),
ui_path: env.komodo_ui_path.unwrap_or(config.ui_path),
ui_index_force_no_cache: env
.komodo_ui_index_force_no_cache
.unwrap_or(config.ui_index_force_no_cache),
+23
View File
@@ -1,6 +1,7 @@
use std::time::Duration;
use anyhow::{Context, anyhow};
use komodo_client::entities::server::Server;
use periphery_client::{
CONNECTION_RETRY_SECONDS, transport::LoginMessage,
};
@@ -18,6 +19,7 @@ use transport::{
use crate::{
config::{core_config, core_connection_query},
monitor::refresh_server_cache,
periphery::PeripheryClient,
state::periphery_connections,
};
@@ -46,6 +48,7 @@ impl PeripheryConnectionArgs<'_> {
let responses = connection.responses.clone();
let _id = id.clone();
tokio::spawn(async move {
loop {
let ws = tokio::select! {
@@ -70,6 +73,14 @@ impl PeripheryConnectionArgs<'_> {
}
};
debug!(
host = identifiers.host(),
query = core_connection_query(),
sec_websocket_accept = accept.to_str().unwrap_or_default(),
resource_id = connection.args.id,
"[PERIPHERY AUTH] Zero trust identifiers"
);
let identifiers = identifiers.build(
accept.as_bytes(),
core_connection_query().as_bytes(),
@@ -86,6 +97,18 @@ impl PeripheryConnectionArgs<'_> {
continue;
};
// Waits until after connection is handled then
// force refreshes the server cache.
let id = _id.clone();
tokio::spawn(async move {
tokio::time::sleep(Duration::from_millis(100)).await;
let Ok(server) = crate::resource::get::<Server>(&id).await
else {
return;
};
refresh_server_cache(&server, true).await;
});
connection.handle_socket(socket, &mut receiver).await
}
});
+22 -8
View File
@@ -1,4 +1,4 @@
use std::str::FromStr;
use std::{str::FromStr, time::Duration};
use anyhow::{Context, anyhow};
use axum::{
@@ -42,6 +42,7 @@ use crate::{
api::write::WriteArgs,
config::core_keys,
helpers::query::id_or_name_filter,
monitor::refresh_server_cache,
resource::KomodoResource,
state::{db_client, periphery_connections},
};
@@ -129,6 +130,14 @@ async fn existing_server_handler(
return;
};
debug!(
host = identifiers.host.to_str().unwrap_or_default(),
query,
sec_websocket_accept = identifiers.accept,
resource_id = &server.id,
"[PERIPHERY AUTH] Zero trust identifiers"
);
let span = info_span!(
"PeripheryLogin",
server_id = server.id,
@@ -155,7 +164,7 @@ async fn existing_server_handler(
socket: &mut socket,
identifiers: identifiers.build(query.as_bytes()),
private_key: core_keys().load().private.as_str(),
public_key_validator: OnboardingKeyValidator { fix_existing_servers_required: true },
public_key_validator: OnboardingKeyValidator { privileged_required: true },
should_close: true
})
.await
@@ -193,6 +202,13 @@ async fn existing_server_handler(
return;
}
// Waits until after connection is handled then
// force refreshes the server cache.
tokio::spawn(async move {
tokio::time::sleep(Duration::from_millis(100)).await;
refresh_server_cache(&server, true).await;
});
connection.handle_socket(socket, &mut receiver).await
}))
}
@@ -219,7 +235,7 @@ async fn fix_existing_server_handler(
socket: &mut socket,
identifiers: identifiers.build(query.as_bytes()),
private_key: core_keys().load().private.as_str(),
public_key_validator: OnboardingKeyValidator { fix_existing_servers_required: true },
public_key_validator: OnboardingKeyValidator { privileged_required: true },
should_close: true,
})
.await
@@ -333,7 +349,7 @@ async fn onboard_new_server_handler(
socket: &mut socket,
identifiers: identifiers.build(query.as_bytes()),
private_key: core_keys().load().private.as_str(),
public_key_validator: OnboardingKeyValidator { fix_existing_servers_required: false },
public_key_validator: OnboardingKeyValidator { privileged_required: false },
should_close: true
})
.await
@@ -497,7 +513,7 @@ async fn create_server_maybe_builder(
}
struct OnboardingKeyValidator {
fix_existing_servers_required: bool,
privileged_required: bool,
}
impl PublicKeyValidator for OnboardingKeyValidator {
@@ -519,9 +535,7 @@ impl PublicKeyValidator for OnboardingKeyValidator {
{
return Err(anyhow!("Onboarding key is invalid"));
}
if self.fix_existing_servers_required
&& !onboarding_key.fix_existing_servers
{
if self.privileged_required && !onboarding_key.privileged {
return Err(anyhow!(
"Onboarding key not able to fix existing servers"
));
+24 -24
View File
@@ -39,34 +39,34 @@ impl ImageDigestCache {
account: Option<String>,
token: Option<String>,
) -> anyhow::Result<ImageDigest> {
if let Some((digest, valid_until)) = self.0.get(&image).await
if let Some((digest, valid_until)) = self.0.get(image).await
// Ensure the query time was within last 10 mins to use cache.
&& valid_until > komodo_timestamp()
{
return Ok(digest);
} else {
let digest = swarm_or_server_request(
&swarm_or_server,
GetLatestImageDigest {
name: image.clone(),
account,
token,
},
)
.await?
.digest;
let digest = ImageDigest::new(image, &digest);
self
.0
.insert(
image,
(digest.clone(), komodo_timestamp() + 10 * 60 * 1_000),
)
.await;
Ok(digest)
}
let digest = swarm_or_server_request(
swarm_or_server,
GetLatestImageDigest {
name: image.clone(),
account,
token,
},
)
.await?
.digest;
let digest = ImageDigest::new(image, &digest);
self
.0
.insert(
image,
(digest.clone(), komodo_timestamp() + 10 * 60 * 1_000),
)
.await;
Ok(digest)
}
}
+321 -65
View File
@@ -228,7 +228,7 @@ async fn execute_execution(
parent_name: &str,
) -> anyhow::Result<()> {
let user = procedure_user().to_owned();
let id = Uuid::new_v4();
let task_id = Uuid::new_v4();
let update = match execution {
Execution::None(_) => return Ok(()),
Execution::RunProcedure(req) => {
@@ -243,7 +243,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RunProcedure"),
@@ -266,7 +270,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RunAction"),
@@ -289,7 +297,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RunBuild"),
@@ -312,7 +324,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at CancelBuild"),
@@ -329,7 +345,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at Deploy"),
@@ -352,7 +372,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PullDeployment"),
@@ -369,7 +393,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StartDeployment"),
@@ -386,7 +414,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RestartDeployment"),
@@ -403,7 +435,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PauseDeployment"),
@@ -420,7 +456,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at UnpauseDeployment"),
@@ -437,7 +477,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StopDeployment"),
@@ -454,7 +498,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at DestroyDeployment"),
@@ -477,7 +525,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at CloneRepo"),
@@ -500,7 +552,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PullRepo"),
@@ -523,7 +579,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at BuildRepo"),
@@ -546,7 +606,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at CancelRepoBuild"),
@@ -563,7 +627,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StartContainer"),
@@ -580,7 +648,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RestartContainer"),
@@ -597,7 +669,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PauseContainer"),
@@ -614,7 +690,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at UnpauseContainer"),
@@ -631,7 +711,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StopContainer"),
@@ -648,7 +732,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RemoveContainer"),
@@ -665,7 +753,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StartAllContainers"),
@@ -682,7 +774,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RestartAllContainers"),
@@ -699,7 +795,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PauseAllContainers"),
@@ -716,7 +816,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at UnpauseAllContainers"),
@@ -733,7 +837,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StopAllContainers"),
@@ -750,7 +858,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PruneContainers"),
@@ -767,7 +879,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at DeleteNetwork"),
@@ -784,7 +900,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PruneNetworks"),
@@ -801,7 +921,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at DeleteImage"),
@@ -818,7 +942,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PruneImages"),
@@ -835,7 +963,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at DeleteVolume"),
@@ -852,7 +984,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PruneVolumes"),
@@ -869,7 +1005,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PruneDockerBuilders"),
@@ -886,7 +1026,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PruneBuildx"),
@@ -903,7 +1047,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PruneSystem"),
@@ -920,7 +1068,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RunSync"),
@@ -943,7 +1095,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at DeployStack"),
@@ -966,7 +1122,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at DeployStackIfChanged"),
@@ -989,7 +1149,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PullStack"),
@@ -1012,7 +1176,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StartStack"),
@@ -1029,7 +1197,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RestartStack"),
@@ -1046,7 +1218,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at PauseStack"),
@@ -1063,7 +1239,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at UnpauseStack"),
@@ -1080,7 +1260,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at StopStack"),
@@ -1097,7 +1281,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at DestroyStack"),
@@ -1114,7 +1302,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RunStackService"),
@@ -1137,7 +1329,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at TestAlerter"),
@@ -1154,7 +1350,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at SendAlert"),
@@ -1171,7 +1371,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RemoveSwarmNodes"),
@@ -1188,7 +1392,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RemoveSwarmStacks"),
@@ -1205,7 +1413,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RemoveSwarmServices"),
@@ -1222,7 +1434,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at CreateSwarmConfig"),
@@ -1239,7 +1455,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RotateSwarmConfig"),
@@ -1256,7 +1476,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RemoveSwarmConfigs"),
@@ -1273,7 +1497,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at CreateSwarmSecret"),
@@ -1290,7 +1518,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RotateSwarmSecret"),
@@ -1307,7 +1539,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RemoveSwarmSecrets"),
@@ -1324,7 +1560,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at ClearRepoCache"),
@@ -1341,7 +1581,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at BackupCoreDatabase"),
@@ -1358,7 +1602,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at GlobalAutoUpdate"),
@@ -1375,7 +1623,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RotateAllServerKeys"),
@@ -1392,7 +1644,11 @@ async fn execute_execution(
let update_id = update.id.clone();
handle_resolve_result(
req
.resolve(&ExecuteArgs { user, update, id })
.resolve(&ExecuteArgs {
user,
update,
task_id,
})
.await
.map_err(|e| e.error)
.context("Failed at RotateCoreKeys"),
+9 -10
View File
@@ -6,7 +6,7 @@ use komodo_client::{
permission::PermissionLevel,
server::Server,
stack::Stack,
terminal::{ContainerTerminalMode, TerminalTarget},
terminal::{ContainerTerminalMode, Terminal, TerminalTarget},
user::User,
},
};
@@ -84,7 +84,7 @@ async fn setup_server_target_for_user(
if let Some(init) = init {
periphery
.request(api::terminal::CreateServerTerminal {
name: terminal.clone(),
name: Some(terminal.clone()),
command: init.command,
recreate: init.recreate,
})
@@ -131,7 +131,7 @@ async fn setup_container_target_for_user(
if let Some(init) = init {
create_container_terminal_inner(
CreateTerminal {
name: terminal.clone(),
name: Some(terminal.clone()),
target: target.clone(),
command: init.command,
mode: init.mode,
@@ -166,7 +166,7 @@ async fn setup_stack_service_target_for_user(
if let Some(init) = init {
create_container_terminal_inner(
CreateTerminal {
name: terminal.clone(),
name: Some(terminal.clone()),
target: target.clone(),
command: init.command,
mode: init.mode,
@@ -199,7 +199,7 @@ async fn setup_deployment_target_for_user(
if let Some(init) = init {
create_container_terminal_inner(
CreateTerminal {
name: terminal.clone(),
name: Some(terminal.clone()),
target: target.clone(),
command: init.command,
mode: init.mode,
@@ -241,7 +241,7 @@ pub async fn create_container_terminal_inner(
}: CreateTerminal,
periphery: &PeripheryClient,
container: String,
) -> anyhow::Result<()> {
) -> anyhow::Result<Terminal> {
match mode.unwrap_or_default() {
ContainerTerminalMode::Exec => periphery
.request(periphery_client::api::terminal::CreateContainerExecTerminal {
@@ -254,7 +254,7 @@ pub async fn create_container_terminal_inner(
.await
.context(
"Failed to create Container Exec Terminal on Periphery",
)?,
),
ContainerTerminalMode::Attach => periphery
.request(periphery_client::api::terminal::CreateContainerAttachTerminal {
name,
@@ -265,9 +265,8 @@ pub async fn create_container_terminal_inner(
.await
.context(
"Failed to create Container Attach Terminal on Periphery",
)?,
};
Ok(())
),
}
}
pub async fn get_stack_service_periphery_container(
+2 -1
View File
@@ -3,7 +3,8 @@ use std::collections::HashMap;
use komodo_client::entities::{
ResourceTarget,
alert::{Alert, AlertData, SeverityLevel},
deployment::{Deployment, DeploymentState}, optional_string,
deployment::{Deployment, DeploymentState},
optional_string,
};
use crate::{
+3 -1
View File
@@ -2,7 +2,9 @@ use std::{collections::HashMap, sync::Mutex};
use anyhow::Context;
use komodo_client::entities::{
alert::AlertDataVariant, permission::PermissionLevel, resource::ResourceQuery, server::Server, swarm::Swarm, user::system_user
alert::AlertDataVariant, permission::PermissionLevel,
resource::ResourceQuery, server::Server, swarm::Swarm,
user::system_user,
};
use crate::resource;
+164 -64
View File
@@ -51,7 +51,7 @@ pub async fn alert_servers(
let mut alerts_to_open = Vec::<(Alert, SendAlerts)>::new();
let mut alerts_to_update = Vec::<(Alert, SendAlerts)>::new();
let mut alert_ids_to_close = Vec::<(Alert, SendAlerts)>::new();
let mut alerts_to_close = Vec::<(Alert, SendAlerts)>::new();
let buffer = alert_buffer();
@@ -66,15 +66,21 @@ pub async fn alert_servers(
let in_maintenance =
is_in_maintenance(&server.config.maintenance_windows, ts);
// ===================
// SERVER HEALTH
// ===================
// ===============
// SERVER HEALTH
// ===============
let health_alert = server_alerts.as_ref().and_then(|alerts| {
alerts.get(&AlertDataVariant::ServerUnreachable)
});
match (server_status.state, health_alert) {
(ServerState::NotOk, None) => {
// Only open unreachable alert if not in maintenance and buffer is ready
match (
server_status.state,
health_alert,
server.config.send_unreachable_alerts,
) {
// Skip alerting if alerts disabled
(ServerState::NotOk, None, false) => {}
(ServerState::NotOk, None, true) => {
// Only open unreachable alert if unreachable alerts enabled and not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -99,19 +105,14 @@ pub async fn alert_servers(
.push((alert, server.config.send_unreachable_alerts))
}
}
(ServerState::NotOk, Some(alert)) => {
(ServerState::NotOk, Some(alert), true) => {
// update alert err
let mut alert = alert.clone();
let (id, name, region) = match alert.data {
AlertData::ServerUnreachable {
id, name, region, ..
} => (id, name, region),
data => {
error!(
"got incorrect alert data in ServerStatus handler. got {data:?}"
);
continue;
}
_ => unreachable!(),
};
alert.data = AlertData::ServerUnreachable {
id,
@@ -124,23 +125,30 @@ pub async fn alert_servers(
alerts_to_update.push((alert, false));
}
// Close an open alert
(ServerState::Ok | ServerState::Disabled, Some(alert)) => {
alert_ids_to_close.push((
(ServerState::NotOk, Some(alert), false) => {
alerts_to_close.push((
alert.clone(),
server.config.send_unreachable_alerts,
));
}
(ServerState::Ok | ServerState::Disabled, None) => buffer
// Close an open alert
(ServerState::Ok | ServerState::Disabled, Some(alert), _) => {
alerts_to_close.push((
alert.clone(),
server.config.send_unreachable_alerts,
));
}
(ServerState::Ok | ServerState::Disabled, None, _) => buffer
.reset(
server_status.id.clone(),
AlertDataVariant::ServerUnreachable,
),
}
// ===================
// ========================
// SERVER VERSION MISMATCH
// ===================
// ========================
let core_version = env!("CARGO_PKG_VERSION");
let mismatched_server_version =
if server_status.state != ServerState::Ok {
@@ -158,9 +166,14 @@ pub async fn alert_servers(
alerts.get(&AlertDataVariant::ServerVersionMismatch)
});
match (mismatched_server_version, version_alert) {
(Some(version), None) => {
// Only open version mismatch alert if not in maintenance and buffer is ready
match (
mismatched_server_version,
version_alert,
server.config.send_version_mismatch_alerts,
) {
(Some(_), None, false) => {}
(Some(version), None, true) => {
// Only open version mismatch alert if version mismatch alerts enabled and not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -187,27 +200,47 @@ pub async fn alert_servers(
.push((alert, server.config.send_version_mismatch_alerts))
}
}
(Some(version), Some(alert)) => {
// Update existing alert with current version info
let mut alert = alert.clone();
alert.data = AlertData::ServerVersionMismatch {
id: server_status.id.clone(),
name: server.name.clone(),
region: optional_string(&server.config.region),
server_version: version.clone(),
core_version: core_version.to_string(),
};
// Don't send notification for updates
alerts_to_update.push((alert, false));
(Some(version), Some(alert), true) => {
// Update existing alert with current version info if changed
let (alert_server_version, alert_core_version) =
match &alert.data {
AlertData::ServerVersionMismatch {
server_version,
core_version,
..
} => (server_version, core_version),
_ => unreachable!(),
};
if alert_server_version != version
|| alert_core_version != core_version
{
let mut alert = alert.clone();
alert.data = AlertData::ServerVersionMismatch {
id: server_status.id.clone(),
name: server.name.clone(),
region: optional_string(&server.config.region),
server_version: version.clone(),
core_version: core_version.to_string(),
};
// Don't send notification for updates
alerts_to_update.push((alert, false));
}
}
(None, Some(alert)) => {
// Version is now correct, close the alert
alert_ids_to_close.push((
(Some(_), Some(alert), false) => {
alerts_to_close.push((
alert.clone(),
server.config.send_version_mismatch_alerts,
));
}
(None, None) => {
(None, Some(alert), _) => {
// Version is now correct, close the alert
alerts_to_close.push((
alert.clone(),
server.config.send_version_mismatch_alerts,
));
}
(None, None, _) => {
// Reset buffer state when no mismatch and no alert
buffer.reset(
server_status.id.clone(),
@@ -227,10 +260,25 @@ pub async fn alert_servers(
.as_ref()
.and_then(|alerts| alerts.get(&AlertDataVariant::ServerCpu))
.cloned();
match (health.cpu.level, cpu_alert, health.cpu.should_close_alert)
{
(SeverityLevel::Warning | SeverityLevel::Critical, None, _) => {
// Only open CPU alert if not in maintenance and buffer is ready
match (
health.cpu.level,
cpu_alert,
health.cpu.should_close_alert,
server.config.send_cpu_alerts,
) {
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
false,
) => {}
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
true,
) => {
// Only open CPU alert if cpu alerts enabled and not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -262,6 +310,7 @@ pub async fn alert_servers(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(mut alert),
_,
true,
) => {
// modify alert level only if it has increased and not in maintenance
if !in_maintenance && alert.level < health.cpu.level {
@@ -280,8 +329,15 @@ pub async fn alert_servers(
.push((alert, server.config.send_cpu_alerts));
}
}
(SeverityLevel::Ok, Some(alert), true) => {
let mut alert = alert.clone();
(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(alert),
_,
false,
) => {
alerts_to_close.push((alert, server.config.send_cpu_alerts));
}
(SeverityLevel::Ok, Some(mut alert), true, _) => {
alert.data = AlertData::ServerCpu {
id: server_status.id.clone(),
name: server.name.clone(),
@@ -292,10 +348,9 @@ pub async fn alert_servers(
.map(|s| s.cpu_perc as f64)
.unwrap_or(0.0),
};
alert_ids_to_close
.push((alert, server.config.send_cpu_alerts))
alerts_to_close.push((alert, server.config.send_cpu_alerts))
}
(SeverityLevel::Ok, _, _) => buffer
(SeverityLevel::Ok, _, _, _) => buffer
.reset(server_status.id.clone(), AlertDataVariant::ServerCpu),
}
@@ -306,10 +361,25 @@ pub async fn alert_servers(
.as_ref()
.and_then(|alerts| alerts.get(&AlertDataVariant::ServerMem))
.cloned();
match (health.mem.level, mem_alert, health.mem.should_close_alert)
{
(SeverityLevel::Warning | SeverityLevel::Critical, None, _) => {
// Only open memory alert if not in maintenance and buffer is ready
match (
health.mem.level,
mem_alert,
health.mem.should_close_alert,
server.config.send_mem_alerts,
) {
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
false,
) => {}
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
true,
) => {
// Only open memory alert if memory alerts enabled and not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -346,6 +416,7 @@ pub async fn alert_servers(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(mut alert),
_,
true,
) => {
// modify alert level only if it has increased and not in maintenance
if !in_maintenance && alert.level < health.mem.level {
@@ -369,7 +440,16 @@ pub async fn alert_servers(
.push((alert, server.config.send_mem_alerts));
}
}
(SeverityLevel::Ok, Some(alert), true) => {
(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(alert),
_,
false,
) => {
alerts_to_close
.push((alert.clone(), server.config.send_mem_alerts));
}
(SeverityLevel::Ok, Some(alert), true, _) => {
let mut alert = alert.clone();
alert.data = AlertData::ServerMem {
id: server_status.id.clone(),
@@ -386,10 +466,9 @@ pub async fn alert_servers(
.map(|s| s.mem_used_gb)
.unwrap_or(0.0),
};
alert_ids_to_close
.push((alert, server.config.send_mem_alerts))
alerts_to_close.push((alert, server.config.send_mem_alerts))
}
(SeverityLevel::Ok, _, _) => buffer
(SeverityLevel::Ok, _, _, _) => buffer
.reset(server_status.id.clone(), AlertDataVariant::ServerMem),
}
@@ -405,13 +484,25 @@ pub async fn alert_servers(
.as_ref()
.and_then(|alerts| alerts.get(path))
.cloned();
match (health.level, disk_alert, health.should_close_alert) {
match (
health.level,
disk_alert,
health.should_close_alert,
server.config.send_disk_alerts,
) {
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
false,
) => {}
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
true,
) => {
// Only open disk alert if not in maintenance and buffer is ready
// Only open disk alert if disk alerts enabled and not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -450,6 +541,7 @@ pub async fn alert_servers(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(mut alert),
_,
true,
) => {
// modify alert level only if it has increased and not in maintenance
if !in_maintenance && health.level < alert.level {
@@ -470,8 +562,16 @@ pub async fn alert_servers(
.push((alert, server.config.send_disk_alerts));
}
}
(SeverityLevel::Ok, Some(alert), true) => {
let mut alert = alert.clone();
(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(alert),
_,
false,
) => {
alerts_to_close
.push((alert, server.config.send_disk_alerts));
}
(SeverityLevel::Ok, Some(mut alert), true, _) => {
let disk =
server_status.system_stats.as_ref().and_then(|stats| {
stats.disks.iter().find(|disk| disk.mount == *path)
@@ -485,10 +585,10 @@ pub async fn alert_servers(
total_gb: disk.map(|d| d.total_gb).unwrap_or_default(),
used_gb: disk.map(|d| d.used_gb).unwrap_or_default(),
};
alert_ids_to_close
alerts_to_close
.push((alert, server.config.send_disk_alerts))
}
(SeverityLevel::Ok, _, _) => buffer.reset(
(SeverityLevel::Ok, _, _, _) => buffer.reset(
server_status.id.clone(),
AlertDataVariant::ServerDisk,
),
@@ -501,7 +601,7 @@ pub async fn alert_servers(
if !health.disks.contains_key(path) {
let mut alert = alert.clone();
alert.level = SeverityLevel::Ok;
alert_ids_to_close
alerts_to_close
.push((alert, server.config.send_disk_alerts));
}
}
@@ -511,7 +611,7 @@ pub async fn alert_servers(
tokio::join!(
open_new_alerts(&alerts_to_open),
update_alerts(&alerts_to_update),
resolve_alerts(&alert_ids_to_close),
resolve_alerts(&alerts_to_close),
);
}
+1 -3
View File
@@ -64,9 +64,7 @@ pub async fn alert_stacks(
let data = AlertData::StackStateChange {
id: status.curr.id.clone(),
name: stack.name,
swarm_name: swarm_names
.get(&stack.config.swarm_id)
.cloned(),
swarm_name: swarm_names.get(&stack.config.swarm_id).cloned(),
swarm_id: optional_string(stack.config.swarm_id),
server_name: server_names
.get(&stack.config.server_id)
+32 -8
View File
@@ -47,7 +47,7 @@ pub async fn alert_swarms(
let mut alerts_to_open = Vec::<(Alert, SendAlerts)>::new();
let mut alerts_to_update = Vec::<(Alert, SendAlerts)>::new();
let mut alert_ids_to_close = Vec::<(Alert, SendAlerts)>::new();
let mut alerts_to_close = Vec::<(Alert, SendAlerts)>::new();
let buffer = alert_buffer();
@@ -68,14 +68,26 @@ pub async fn alert_swarms(
let health_alert = swarm_alerts.as_ref().and_then(|alerts| {
alerts.get(&AlertDataVariant::SwarmUnhealthy)
});
match (swarm_status.state, health_alert) {
match (
swarm_status.state,
health_alert,
swarm.config.send_unhealthy_alerts,
) {
(
SwarmState::Unhealthy
| SwarmState::Down
| SwarmState::Unknown,
None,
false,
) => {}
(
SwarmState::Unhealthy
| SwarmState::Down
| SwarmState::Unknown,
None,
true,
) => {
// Only open unreachable alert if not in maintenance and buffer is ready
// Only open unhealthy alert if unhealthy alerts enabled and not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
swarm_status.id.clone(),
@@ -104,6 +116,7 @@ pub async fn alert_swarms(
| SwarmState::Down
| SwarmState::Unknown,
Some(alert),
true,
) => {
// update alert err
let mut alert = alert.clone();
@@ -126,12 +139,23 @@ pub async fn alert_swarms(
alerts_to_update.push((alert, false));
}
// Close an open alert
(SwarmState::Healthy, Some(alert)) => {
alert_ids_to_close
(
SwarmState::Unhealthy
| SwarmState::Down
| SwarmState::Unknown,
Some(alert),
false,
) => {
alerts_to_close
.push((alert.clone(), swarm.config.send_unhealthy_alerts));
}
(SwarmState::Healthy, None) => buffer.reset(
// Close an open alert
(SwarmState::Healthy, Some(alert), _) => {
alerts_to_close
.push((alert.clone(), swarm.config.send_unhealthy_alerts));
}
(SwarmState::Healthy, None, _) => buffer.reset(
swarm_status.id.clone(),
AlertDataVariant::SwarmUnhealthy,
),
@@ -141,7 +165,7 @@ pub async fn alert_swarms(
tokio::join!(
open_new_alerts(&alerts_to_open),
update_alerts(&alerts_to_update),
resolve_alerts(&alert_ids_to_close),
resolve_alerts(&alerts_to_close),
);
}
+180 -168
View File
@@ -41,7 +41,7 @@ mod record;
mod resources;
mod swarm;
pub use swarm::update_cache_for_swarm;
pub use swarm::refresh_swarm_cache;
const ADDITIONAL_MS: u128 = 500;
@@ -52,17 +52,17 @@ pub fn spawn_monitoring_loops() {
fn spawn_server_monitoring_loop() {
tokio::spawn(async move {
refresh_server_cache(komodo_timestamp()).await;
refresh_all_server_cache(komodo_timestamp()).await;
let interval = monitoring_interval();
loop {
let ts = (wait_until_timelength(interval, ADDITIONAL_MS).await
- ADDITIONAL_MS) as i64;
refresh_server_cache(ts).await;
refresh_all_server_cache(ts).await;
}
});
}
async fn refresh_server_cache(ts: i64) {
async fn refresh_all_server_cache(ts: i64) {
let servers =
match find_collect(&db_client().servers, None, None).await {
Ok(servers) => servers,
@@ -74,7 +74,7 @@ async fn refresh_server_cache(ts: i64) {
}
};
let futures = servers.into_iter().map(|server| async move {
update_cache_for_server(&server, false).await;
refresh_server_cache(&server, false).await;
});
join_all(futures).await;
tokio::join!(check_alerts(ts), record_server_stats(ts));
@@ -82,7 +82,7 @@ async fn refresh_server_cache(ts: i64) {
/// Makes sure cache for server doesn't update too frequently / simultaneously.
/// If forced, will still block against simultaneous update.
fn update_cache_for_server_controller()
fn refresh_server_cache_controller()
-> &'static CloneCache<String, Arc<Mutex<i64>>> {
static CACHE: OnceLock<CloneCache<String, Arc<Mutex<i64>>>> =
OnceLock::new();
@@ -93,188 +93,176 @@ fn update_cache_for_server_controller()
/// which exits early if the lock is busy or it was completed too recently.
/// If force is true, it will wait on simultaneous calls, and will
/// ignore the restriction on being completed too recently.
pub async fn update_cache_for_server(server: &Server, force: bool) {
// Concurrency controller to ensure it isn't done too often
// when it happens in other contexts.
let controller = update_cache_for_server_controller()
.get_or_insert_default(&server.id)
.await;
let mut lock = match controller.try_lock() {
Ok(lock) => lock,
Err(_) if force => controller.lock().await,
Err(_) => return,
};
///
/// Returns impl Future for explicit Send bound, as this function
/// calls `periphery_client` which in some paths calls back this function `refresh_server_cache`.
/// While infinite recursion is prevented, the compiler needs some help to know the Send bound.
///
/// Clippy is not aware of this requirement, so the `manual_async_fn` lint is allowed here.
#[allow(clippy::manual_async_fn)]
pub fn refresh_server_cache(
server: &Server,
force: bool,
) -> impl Future<Output = ()> + Send + '_ {
async move {
// Concurrency controller to ensure it isn't done too often
// when it happens in other contexts.
let controller = refresh_server_cache_controller()
.get_or_insert_default(&server.id)
.await;
let mut lock = match controller.try_lock() {
Ok(lock) => lock,
Err(_) if force => controller.lock().await,
Err(_) => return,
};
let now = komodo_timestamp();
let now = komodo_timestamp();
// early return if called again sooner than 1s.
if !force && *lock > now - 1_000 {
return;
}
// early return if called again sooner than 1s.
if !force && *lock > now - 1_000 {
return;
}
*lock = now;
*lock = now;
let resources = UpdateCacheResources::load_server(server).await;
let resources = RefreshCacheResources::load_server(server).await;
// Handle server disabled
if !server.config.enabled {
resources.insert_status_unknown().await;
insert_server_status(
server,
ServerState::Disabled,
None,
None,
None,
None,
None,
)
.await;
periphery_connections().remove(&server.id).await;
return;
}
let periphery = match periphery_client(server).await {
Ok(periphery) => periphery,
Err(e) => {
resources.insert_status_unknown().await;
insert_server_status(
server,
ServerState::NotOk,
None,
None,
None,
None,
Serror::from(&e),
)
.await;
return;
}
};
let PollStatusResponse {
periphery_info,
system_info,
system_stats,
mut docker,
} = match periphery
.request(api::poll::PollStatus {
include_stats: server.config.stats_monitoring,
include_docker: true,
})
.await
{
Ok(info) => info,
Err(e) => {
resources.insert_status_unknown().await;
insert_server_status(
server,
ServerState::NotOk,
None,
None,
None,
None,
Serror::from(&e),
)
.await;
return;
}
};
if let Some(docker) = &mut docker {
docker.containers.iter_mut().for_each(|container| {
container.server_id = Some(server.id.clone())
});
}
let containers = docker
.as_ref()
.map(|docker| docker.containers.as_slice())
.unwrap_or(&[]);
let images = docker
.as_ref()
.map(|docker| docker.images.as_slice())
.unwrap_or(&[]);
tokio::join!(
resources::update_server_stack_cache(
resources.stacks,
containers,
images
),
resources::update_server_deployment_cache(
resources.deployments,
containers,
images,
),
);
// Handle server disabled
if !server.config.enabled {
resources.insert_status_unknown().await;
insert_server_status(
server,
ServerState::Disabled,
None,
None,
None,
None,
ServerState::Ok,
Some(periphery_info),
Some(system_info),
system_stats.map(|stats| filter_volumes(server, stats)),
docker,
None,
)
.await;
periphery_connections().remove(&server.id).await;
return;
}
let periphery = match periphery_client(server).await {
Ok(periphery) => periphery,
Err(e) => {
resources.insert_status_unknown().await;
insert_server_status(
server,
ServerState::NotOk,
None,
None,
None,
None,
Serror::from(&e),
)
.await;
return;
let status_cache = repo_status_cache();
for repo in resources.repos {
let (latest_hash, latest_message) = periphery
.request(GetLatestCommit {
name: repo.name.clone(),
path: optional_string(&repo.config.path),
})
.await
.ok()
.flatten()
.map(|c| (c.hash, c.message))
.unzip();
status_cache
.insert(
repo.id,
CachedRepoStatus {
latest_hash,
latest_message,
}
.into(),
)
.await;
}
};
let PollStatusResponse {
periphery_info,
system_info,
system_stats,
mut docker,
} = match periphery
.request(api::poll::PollStatus {
include_stats: server.config.stats_monitoring,
include_docker: true,
})
.await
{
Ok(info) => info,
Err(e) => {
resources.insert_status_unknown().await;
insert_server_status(
server,
ServerState::NotOk,
None,
None,
None,
None,
Serror::from(&e),
)
.await;
return;
}
};
if let Some(docker) = &mut docker {
docker.containers.iter_mut().for_each(|container| {
container.server_id = Some(server.id.clone())
});
}
let containers = docker
.as_ref()
.map(|docker| docker.containers.as_slice())
.unwrap_or(&[]);
let images = docker
.as_ref()
.map(|docker| docker.images.as_slice())
.unwrap_or(&[]);
tokio::join!(
resources::update_server_stack_cache(
resources.stacks,
containers,
images
),
resources::update_server_deployment_cache(
resources.deployments,
containers,
images,
),
);
insert_server_status(
server,
ServerState::Ok,
Some(periphery_info),
Some(system_info),
system_stats.map(|stats| filter_volumes(server, stats)),
docker,
None,
)
.await;
let status_cache = repo_status_cache();
for repo in resources.repos {
let (latest_hash, latest_message) = periphery
.request(GetLatestCommit {
name: repo.name.clone(),
path: optional_string(&repo.config.path),
})
.await
.ok()
.flatten()
.map(|c| (c.hash, c.message))
.unzip();
status_cache
.insert(
repo.id,
CachedRepoStatus {
latest_hash,
latest_message,
}
.into(),
)
.await;
}
}
struct UpdateCacheResources {
struct RefreshCacheResources {
stacks: Vec<Stack>,
deployments: Vec<Deployment>,
repos: Vec<Repo>,
}
impl UpdateCacheResources {
pub async fn load_swarm(swarm: &Swarm) -> Self {
let (stacks, deployments) = tokio::join!(
find_collect(
&db_client().stacks,
doc! { "config.swarm_id": &swarm.id },
None,
),
find_collect(
&db_client().deployments,
doc! { "config.swarm_id": &swarm.id },
None,
),
);
let stacks = stacks.inspect_err(|e| error!("Failed to get stacks list from db (update swarm status cache) | swarm: {} | {e:#}", swarm.name)).unwrap_or_default();
let deployments = deployments.inspect_err(|e| error!("Failed to get deployments list from db (update swarm status cache) | swarm : {} | {e:#}", swarm.name)).unwrap_or_default();
Self {
stacks,
deployments,
repos: Default::default(),
}
}
impl RefreshCacheResources {
pub async fn load_server(server: &Server) -> Self {
let (stacks, deployments, repos) = tokio::join!(
find_collect(
@@ -305,6 +293,30 @@ impl UpdateCacheResources {
}
}
pub async fn load_swarm(swarm: &Swarm) -> Self {
let (stacks, deployments) = tokio::join!(
find_collect(
&db_client().stacks,
doc! { "config.swarm_id": &swarm.id },
None,
),
find_collect(
&db_client().deployments,
doc! { "config.swarm_id": &swarm.id },
None,
),
);
let stacks = stacks.inspect_err(|e| error!("Failed to get stacks list from db (update swarm status cache) | swarm: {} | {e:#}", swarm.name)).unwrap_or_default();
let deployments = deployments.inspect_err(|e| error!("Failed to get deployments list from db (update swarm status cache) | swarm : {} | {e:#}", swarm.name)).unwrap_or_default();
Self {
stacks,
deployments,
repos: Default::default(),
}
}
pub async fn insert_status_unknown(self) {
insert_stacks_status_unknown(self.stacks).await;
insert_deployments_status_unknown(self.deployments).await;
+9 -9
View File
@@ -23,7 +23,7 @@ use crate::{
config::monitoring_interval,
helpers::swarm::swarm_request_custom_timeout,
monitor::{
UpdateCacheResources,
RefreshCacheResources,
resources::{
update_swarm_deployment_cache, update_swarm_stack_cache,
},
@@ -35,16 +35,16 @@ const ADDITIONAL_MS: u128 = 1000;
pub fn spawn_swarm_monitoring_loop() {
tokio::spawn(async move {
refresh_swarm_cache().await;
refresh_all_swarm_cache().await;
let interval = monitoring_interval();
loop {
wait_until_timelength(interval, ADDITIONAL_MS).await;
refresh_swarm_cache().await;
refresh_all_swarm_cache().await;
}
});
}
async fn refresh_swarm_cache() {
async fn refresh_all_swarm_cache() {
let swarms =
match find_collect(&db_client().swarms, None, None).await {
Ok(swarms) => swarms,
@@ -56,7 +56,7 @@ async fn refresh_swarm_cache() {
}
};
let futures = swarms.into_iter().map(|swarm| async move {
update_cache_for_swarm(&swarm, false).await;
refresh_swarm_cache(&swarm, false).await;
});
join_all(futures).await;
// tokio::join!(check_alerts(ts), record_swarm_stats(ts));
@@ -64,7 +64,7 @@ async fn refresh_swarm_cache() {
/// Makes sure cache for swarm doesn't update too frequently / simultaneously.
/// If forced, will still block against simultaneous update.
fn update_cache_for_swarm_controller()
fn refresh_swarm_cache_controller()
-> &'static CloneCache<String, Arc<Mutex<i64>>> {
static CACHE: OnceLock<CloneCache<String, Arc<Mutex<i64>>>> =
OnceLock::new();
@@ -75,10 +75,10 @@ fn update_cache_for_swarm_controller()
/// which exits early if the lock is busy or it was completed too recently.
/// If force is true, it will wait on simultaneous calls, and will
/// ignore the restriction on being completed too recently.
pub async fn update_cache_for_swarm(swarm: &Swarm, force: bool) {
pub async fn refresh_swarm_cache(swarm: &Swarm, force: bool) {
// Concurrency controller to ensure it isn't done too often
// when it happens in other contexts.
let controller = update_cache_for_swarm_controller()
let controller = refresh_swarm_cache_controller()
.get_or_insert_default(&swarm.id)
.await;
let mut lock = match controller.try_lock() {
@@ -96,7 +96,7 @@ pub async fn update_cache_for_swarm(swarm: &Swarm, force: bool) {
*lock = now;
let resources = UpdateCacheResources::load_swarm(swarm).await;
let resources = RefreshCacheResources::load_swarm(swarm).await;
if swarm.config.server_ids.is_empty() {
resources.insert_status_unknown().await;
+10 -4
View File
@@ -33,7 +33,7 @@ use crate::{
query::{get_deployment_state, get_swarm_or_server},
swarm::swarm_request,
},
monitor::{update_cache_for_server, update_cache_for_swarm},
monitor::{refresh_server_cache, refresh_swarm_cache},
state::{action_states, db_client, deployment_status_cache},
};
@@ -72,7 +72,13 @@ impl super::KomodoResource for Deployment {
fn inherit_specific_permissions_from(
_self: &Resource<Self::Config, Self::Info>,
) -> Option<ResourceTarget> {
ResourceTarget::Server(_self.config.server_id.clone()).into()
if !_self.config.swarm_id.is_empty() {
Some(ResourceTarget::Swarm(_self.config.swarm_id.clone()))
} else if !_self.config.server_id.is_empty() {
Some(ResourceTarget::Server(_self.config.server_id.clone()))
} else {
None
}
}
fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
@@ -221,10 +227,10 @@ impl super::KomodoResource for Deployment {
};
match swarm_or_server {
SwarmOrServer::Swarm(swarm) => {
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
SwarmOrServer::Server(server) => {
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
}
SwarmOrServer::None => {}
}
+3 -3
View File
@@ -24,7 +24,7 @@ use periphery_client::api;
use crate::{
config::core_config,
helpers::periphery_client,
monitor::update_cache_for_server,
monitor::refresh_server_cache,
state::{
action_states, db_client, periphery_connections,
server_status_cache,
@@ -151,7 +151,7 @@ impl super::KomodoResource for Server {
created: &Resource<Self::Config, Self::Info>,
_update: &mut Update,
) -> anyhow::Result<()> {
update_cache_for_server(created, true).await;
refresh_server_cache(created, true).await;
Ok(())
}
@@ -173,7 +173,7 @@ impl super::KomodoResource for Server {
updated: &Self,
_update: &mut Update,
) -> anyhow::Result<()> {
update_cache_for_server(updated, true).await;
refresh_server_cache(updated, true).await;
Ok(())
}
+10 -4
View File
@@ -35,7 +35,7 @@ use crate::{
repo_link,
swarm::swarm_request,
},
monitor::{update_cache_for_server, update_cache_for_swarm},
monitor::{refresh_server_cache, refresh_swarm_cache},
state::{
action_states, all_resources_cache, db_client,
server_status_cache, stack_status_cache,
@@ -77,7 +77,13 @@ impl super::KomodoResource for Stack {
fn inherit_specific_permissions_from(
_self: &Resource<Self::Config, Self::Info>,
) -> Option<ResourceTarget> {
ResourceTarget::Server(_self.config.server_id.clone()).into()
if !_self.config.swarm_id.is_empty() {
Some(ResourceTarget::Swarm(_self.config.swarm_id.clone()))
} else if !_self.config.server_id.is_empty() {
Some(ResourceTarget::Server(_self.config.server_id.clone()))
} else {
None
}
}
fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
@@ -294,10 +300,10 @@ impl super::KomodoResource for Stack {
};
match swarm_or_server {
SwarmOrServer::Swarm(swarm) => {
update_cache_for_swarm(&swarm, true).await;
refresh_swarm_cache(&swarm, true).await;
}
SwarmOrServer::Server(server) => {
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
}
SwarmOrServer::None => {}
}
+3 -3
View File
@@ -15,7 +15,7 @@ use komodo_client::entities::{
use crate::{
config::core_config,
monitor::update_cache_for_swarm,
monitor::refresh_swarm_cache,
state::{db_client, swarm_status_cache},
};
@@ -89,7 +89,7 @@ impl super::KomodoResource for Swarm {
created: &Self,
_update: &mut Update,
) -> anyhow::Result<()> {
update_cache_for_swarm(created, true).await;
refresh_swarm_cache(created, true).await;
Ok(())
}
@@ -111,7 +111,7 @@ impl super::KomodoResource for Swarm {
updated: &Self,
_update: &mut Update,
) -> anyhow::Result<()> {
update_cache_for_swarm(updated, true).await;
refresh_swarm_cache(updated, true).await;
Ok(())
}
+6 -8
View File
@@ -10,12 +10,7 @@ use komodo_client::{
permission::PermissionLevel,
repo::Repo,
resource::Resource,
sync::{
PartialResourceSyncConfig, ResourceSync, ResourceSyncConfig,
ResourceSyncConfigDiff, ResourceSyncInfo, ResourceSyncListItem,
ResourceSyncListItemInfo, ResourceSyncQuerySpecifics,
ResourceSyncState,
},
sync::*,
update::Update,
user::{User, sync_user},
},
@@ -260,12 +255,15 @@ async fn get_resource_sync_state(
{
return state;
}
if data.pending_error.is_some() || !data.remote_errors.is_empty() {
if data.pending_error.is_some()
|| data.pending_deploy_error.is_some()
|| !data.remote_errors.is_empty()
{
ResourceSyncState::Failed
} else if !data.resource_updates.is_empty()
|| !data.variable_updates.is_empty()
|| !data.user_group_updates.is_empty()
|| data.pending_deploy.to_deploy > 0
|| !data.pending_deploys.is_empty()
{
ResourceSyncState::Pending
} else {
+2 -2
View File
@@ -109,7 +109,7 @@ pub fn spawn_schedule_executor() {
.resolve(&ExecuteArgs {
user: action_user().to_owned(),
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
{
@@ -180,7 +180,7 @@ pub fn spawn_schedule_executor() {
.resolve(&ExecuteArgs {
user: procedure_user().to_owned(),
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
{
+2 -2
View File
@@ -14,7 +14,7 @@ use periphery_client::api::compose::*;
use crate::{
helpers::{periphery_client, update::update_update},
monitor::update_cache_for_server,
monitor::refresh_server_cache,
periphery::PeripheryClient,
state::action_states,
};
@@ -102,7 +102,7 @@ pub async fn execute_compose_with_stack_and_server<
.push(T::execute(periphery, stack, services, extras).await?);
// Ensure cached stack state up to date by updating server cache
update_cache_for_server(&server, true).await;
refresh_server_cache(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
+20 -20
View File
@@ -1,7 +1,6 @@
use std::str::FromStr;
use anyhow::Context;
use colored::Colorize;
use database::mungos::{
find::find_collect,
mongodb::bson::{
@@ -33,6 +32,7 @@ use komodo_client::{
user::{action_user, system_user},
},
};
use mogh_auth_server::api::login::local::sign_up_local_user;
use mogh_resolver::Resolve;
use uuid::Uuid;
@@ -41,6 +41,7 @@ use crate::{
execute::{ExecuteArgs, ExecuteRequest},
write::WriteArgs,
},
auth::KomodoAuthImpl,
config::core_config,
helpers::update::init_execution_update,
network, resource,
@@ -91,7 +92,7 @@ pub async fn run_startup_actions() {
.resolve(&ExecuteArgs {
user: action_user().to_owned(),
update,
id: Uuid::new_v4(),
task_id: Uuid::new_v4(),
})
.await
{
@@ -301,7 +302,7 @@ async fn ensure_init_user_and_resources() {
// Assumes if there are any existing users, procedures, or tags,
// the default procedures do not need to be set up.
let Ok((None, None, None)) = tokio::try_join!(
let Ok((None, procedures, tags)) = tokio::try_join!(
db.users.find_one(Document::new()),
db.procedures.find_one(Document::new()),
db.tags.find_one(Document::new()),
@@ -314,20 +315,16 @@ async fn ensure_init_user_and_resources() {
// Init admin user if set in config.
if let Some(username) = &config.init_admin_username {
info!("Creating init admin user...");
// if let Err(e) = (SignUpLocalUser {
// username: username.clone(),
// password: config.init_admin_password.clone(),
// })
// .resolve(&AuthArgs {
// headers: Default::default(),
// ip: IpAddr::V4(Ipv4Addr::UNSPECIFIED),
// session: None,
// })
// .await
// {
// error!("Failed to create init admin user | {:#}", e.error);
// return;
// }
if let Err(e) = sign_up_local_user(
&KomodoAuthImpl,
username.to_string(),
&config.init_admin_password,
)
.await
{
error!("Failed to create init admin user | {:#}", e.error);
return;
}
match db
.users
.find_one(doc! { "username": username })
@@ -347,12 +344,15 @@ async fn ensure_init_user_and_resources() {
}
}
if config.disable_init_resources {
info!("System resources init {}", "DISABLED".red());
if config.disable_init_resources
|| procedures.is_some()
|| tags.is_some()
{
info!("Skipping initial system resource creation");
return;
}
info!("Creating init system resources...");
info!("Creating initial system resources...");
let write_args = WriteArgs {
user: system_user().to_owned(),
+1 -1
View File
@@ -220,5 +220,5 @@ pub fn all_resources_cache() -> &'static ArcSwap<AllResourcesById> {
pub fn image_digest_cache() -> &'static ImageDigestCache {
static IMAGE_DIGEST_CACHE: OnceLock<Arc<ImageDigestCache>> =
OnceLock::new();
IMAGE_DIGEST_CACHE.get_or_init(|| ImageDigestCache::new())
IMAGE_DIGEST_CACHE.get_or_init(ImageDigestCache::new)
}
+27 -54
View File
@@ -18,7 +18,7 @@ use komodo_client::{
PartialStackConfig, Stack, StackConfig,
StackRemoteFileContents, StackState,
},
sync::SyncDeployUpdate,
sync::SyncDeployTarget,
toml::ResourceToml,
update::Log,
user::sync_user,
@@ -41,8 +41,7 @@ use super::ResourceSyncTrait;
/// All entries in here are due to be deployed,
/// after the given dependencies,
/// with the given reason.
pub type ToDeployCache =
Vec<(ResourceTarget, String, Vec<ResourceTarget>)>;
pub type ToDeployCache = Vec<SyncDeployTarget>;
#[derive(Clone, Copy)]
pub struct SyncDeployParams<'a> {
@@ -72,14 +71,16 @@ pub async fn deploy_from_cache(
// Collect all waiting deployments without waiting dependencies.
let good_to_deploy = to_deploy
.iter()
.filter(|(_, _, after)| {
to_deploy
.iter()
.all(|(target, _, _)| !after.contains(target))
.filter(|SyncDeployTarget { after, .. }| {
to_deploy.iter().all(|SyncDeployTarget { target, .. }| {
!after.contains(target)
})
})
// The target / reason need the be cloned out to to_deploy is not borrowed from.
// to_deploy will be mutably accessed later.
.map(|(target, reason, _)| (target.clone(), reason.clone()))
.map(|SyncDeployTarget { target, reason, .. }| {
(target.clone(), reason.clone())
})
.collect::<HashMap<_, _>>();
// Deploy the ones ready for deployment
@@ -103,7 +104,7 @@ pub async fn deploy_from_cache(
.resolve(&ExecuteArgs {
user: user.to_owned(),
update,
id,
task_id: id,
})
.await
}
@@ -122,7 +123,7 @@ pub async fn deploy_from_cache(
.resolve(&ExecuteArgs {
user: user.to_owned(),
update,
id,
task_id: id,
})
.await
}
@@ -172,8 +173,9 @@ pub async fn deploy_from_cache(
}
// Remove the deployed ones from 'to_deploy'
to_deploy
.retain(|(target, _, _)| !good_to_deploy.contains_key(target));
to_deploy.retain(|SyncDeployTarget { target, .. }| {
!good_to_deploy.contains_key(target)
});
// If there must be another round, these are dependent on the first round.
// Sleep for 1s to allow for first round to startup
@@ -196,46 +198,10 @@ pub async fn deploy_from_cache(
pub async fn get_updates_for_view(
params: SyncDeployParams<'_>,
) -> SyncDeployUpdate {
let inner = async {
let mut update = SyncDeployUpdate {
to_deploy: 0,
log: String::from("Deploy Updates\n-------------------\n"),
};
let mut lines = Vec::<String>::new();
for (target, reason, after) in build_deploy_cache(params).await? {
update.to_deploy += 1;
let mut line = format!(
"{}: {}. reason: {reason}",
colored("Deploy", Color::Green),
bold(format!("{target:?}")),
);
if !after.is_empty() {
line.push_str(&format!(
"\n{}: {}",
colored("After", Color::Blue),
after
.iter()
.map(|target| format!("{target:?}"))
.collect::<Vec<_>>()
.join(", ")
))
}
lines.push(line);
}
update.log.push_str(&lines.join("\n-------------------\n"));
anyhow::Ok(update)
};
match inner.await {
Ok(res) => res,
Err(e) => SyncDeployUpdate {
to_deploy: 0,
log: format_serror(
&e.context("failed to get deploy updates for view").into(),
),
},
) -> (Vec<SyncDeployTarget>, Option<String>) {
match build_deploy_cache(params).await {
Ok(targets) => (targets, None),
Err(e) => (Vec::new(), Some(format_serror(&e.into()))),
}
}
@@ -294,7 +260,11 @@ pub async fn build_deploy_cache(
.map(|(target, (reason, mut after))| {
// Only keep targets which are deploying.
after.retain(|target| clone.contains_key(target));
(target, reason, after)
SyncDeployTarget {
target,
reason,
after,
}
})
.collect(),
)
@@ -620,9 +590,12 @@ fn build_cache_for_stack<'a>(
|| diff.extra_args.is_some()
|| diff.environment.is_some()
|| diff.env_file_path.is_some()
|| diff.additional_env_files.is_some()
|| diff.linked_repo.is_some()
|| diff.repo.is_some()
|| diff.branch.is_some()
|| diff.commit.is_some();
|| diff.commit.is_some()
|| diff.compose_cmd_wrapper.is_some();
if changed {
cache.insert(
target,
+150 -475
View File
@@ -35,17 +35,6 @@ use super::{
include_resource_by_tags,
};
impl ResourceSyncTrait for Swarm {
fn get_diff(
original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
Ok(original.partial_diff(update))
}
}
impl ExecuteResourceSync for Swarm {}
impl ResourceSyncTrait for Server {
fn get_diff(
original: Self::Config,
@@ -57,20 +46,41 @@ impl ResourceSyncTrait for Server {
impl ExecuteResourceSync for Server {}
impl ResourceSyncTrait for Swarm {
fn get_diff(
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let all = all_resources_cache().load();
original.server_ids.iter_mut().for_each(|server_id| {
*server_id = all
.servers
.get(server_id)
.map(|s| s.name.clone())
.unwrap_or_default();
});
Ok(original.partial_diff(update))
}
}
impl ExecuteResourceSync for Swarm {}
impl ResourceSyncTrait for Deployment {
fn get_diff(
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let resources = all_resources_cache().load();
let all = all_resources_cache().load();
original.swarm_id = resources
original.swarm_id = all
.swarms
.get(&original.swarm_id)
.map(|s| s.name.clone())
.unwrap_or_default();
original.server_id = resources
original.server_id = all
.servers
.get(&original.server_id)
.map(|s| s.name.clone())
@@ -80,7 +90,7 @@ impl ResourceSyncTrait for Deployment {
&original.image
{
original.image = DeploymentImage::Build {
build_id: resources
build_id: all
.builds
.get(build_id)
.map(|b| b.name.clone())
@@ -100,21 +110,21 @@ impl ResourceSyncTrait for Stack {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let resources = all_resources_cache().load();
let all = all_resources_cache().load();
original.swarm_id = resources
original.swarm_id = all
.swarms
.get(&original.swarm_id)
.map(|s| s.name.clone())
.unwrap_or_default();
original.server_id = resources
original.server_id = all
.servers
.get(&original.server_id)
.map(|s| s.name.clone())
.unwrap_or_default();
original.linked_repo = resources
original.linked_repo = all
.repos
.get(&original.linked_repo)
.map(|r| r.name.clone())
@@ -131,13 +141,13 @@ impl ResourceSyncTrait for Build {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let resources = all_resources_cache().load();
original.builder_id = resources
let all = all_resources_cache().load();
original.builder_id = all
.builders
.get(&original.builder_id)
.map(|b| b.name.clone())
.unwrap_or_default();
original.linked_repo = resources
original.linked_repo = all
.repos
.get(&original.linked_repo)
.map(|r| r.name.clone())
@@ -165,16 +175,16 @@ impl ResourceSyncTrait for Repo {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let resources = all_resources_cache().load();
let all = all_resources_cache().load();
// Need to replace server id with name
original.server_id = resources
original.server_id = all
.servers
.get(&original.server_id)
.map(|s| s.name.clone())
.unwrap_or_default();
// Need to replace builder id with name
original.builder_id = resources
original.builder_id = all
.builders
.get(&original.builder_id)
.map(|s| s.name.clone())
@@ -204,8 +214,8 @@ impl ResourceSyncTrait for Builder {
) -> anyhow::Result<Self::ConfigDiff> {
// need to replace server builder id with name
if let BuilderConfig::Server(config) = &mut original {
let resources = all_resources_cache().load();
config.server_id = resources
let all = all_resources_cache().load();
config.server_id = all
.servers
.get(&config.server_id)
.map(|s| s.name.clone())
@@ -313,8 +323,8 @@ impl ResourceSyncTrait for ResourceSync {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let resources = all_resources_cache().load();
original.linked_repo = resources
let all = all_resources_cache().load();
original.linked_repo = all
.repos
.get(&original.linked_repo)
.map(|r| r.name.clone())
@@ -331,456 +341,121 @@ impl ResourceSyncTrait for Procedure {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let resources = all_resources_cache().load();
let all = all_resources_cache().load();
for stage in &mut original.stages {
for execution in &mut stage.executions {
match &mut execution.execution {
Execution::None(_) => {}
Execution::RunProcedure(config) => {
config.procedure = resources
.procedures
.get(&config.procedure)
.map(|p| p.name.clone())
.unwrap_or_default();
}
Execution::BatchRunProcedure(_config) => {}
Execution::RunAction(config) => {
config.action = resources
.actions
.get(&config.action)
.map(|p| p.name.clone())
.unwrap_or_default();
}
Execution::BatchRunAction(_config) => {}
Execution::RunBuild(config) => {
config.build = resources
.builds
.get(&config.build)
.map(|b| b.name.clone())
.unwrap_or_default();
}
Execution::BatchRunBuild(_config) => {}
Execution::CancelBuild(config) => {
config.build = resources
.builds
.get(&config.build)
.map(|b| b.name.clone())
.unwrap_or_default();
}
Execution::Deploy(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::BatchDeploy(_config) => {}
Execution::PullDeployment(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::StartDeployment(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::RestartDeployment(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PauseDeployment(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::UnpauseDeployment(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::StopDeployment(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::DestroyDeployment(config) => {
config.deployment = resources
.deployments
.get(&config.deployment)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::BatchDestroyDeployment(_config) => {}
Execution::CloneRepo(config) => {
config.repo = resources
.repos
.get(&config.repo)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::BatchCloneRepo(_config) => {}
Execution::PullRepo(config) => {
config.repo = resources
.repos
.get(&config.repo)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::BatchPullRepo(_config) => {}
Execution::BuildRepo(config) => {
config.repo = resources
.repos
.get(&config.repo)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::BatchBuildRepo(_config) => {}
Execution::CancelRepoBuild(config) => {
config.repo = resources
.repos
.get(&config.repo)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::StartContainer(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::RestartContainer(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PauseContainer(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::UnpauseContainer(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::StopContainer(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::DestroyContainer(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::StartAllContainers(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::RestartAllContainers(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PauseAllContainers(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::UnpauseAllContainers(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::StopAllContainers(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PruneContainers(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::DeleteNetwork(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PruneNetworks(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::DeleteImage(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PruneImages(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::DeleteVolume(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PruneVolumes(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PruneDockerBuilders(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PruneBuildx(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::PruneSystem(config) => {
config.server = resources
.servers
.get(&config.server)
.map(|d| d.name.clone())
.unwrap_or_default();
}
Execution::RunSync(config) => {
config.sync = resources
.syncs
.get(&config.sync)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::CommitSync(config) => {
config.sync = resources
.syncs
.get(&config.sync)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::DeployStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::BatchDeployStack(_config) => {}
Execution::DeployStackIfChanged(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::BatchDeployStackIfChanged(_config) => {}
Execution::PullStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::BatchPullStack(_config) => {}
Execution::StartStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RestartStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::PauseStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::UnpauseStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::StopStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::DestroyStack(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RunStackService(config) => {
config.stack = resources
.stacks
.get(&config.stack)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::BatchDestroyStack(_config) => {}
Execution::TestAlerter(config) => {
config.alerter = resources
.alerters
.get(&config.alerter)
.map(|a| a.name.clone())
.unwrap_or_default();
}
Execution::SendAlert(config) => {
config.alerters = config
.alerters
.iter()
.map(|alerter| {
resources
// Replaces an id field on config with the resource name from `all`.
macro_rules! replace_id_with_name {
($($Variant:ident => $field:ident, $collection:ident);* $(;)?) => {
match &mut execution.execution {
$(
Execution::$Variant(config) => {
config.$field = all
.$collection
.get(&config.$field)
.map(|r| r.name.clone())
.unwrap_or_default();
}
)*
// SendAlert maps a Vec of alerter ids
Execution::SendAlert(config) => {
config.alerters = config
.alerters
.get(alerter)
.map(|a| a.name.clone())
.unwrap_or_default()
})
.collect();
}
Execution::RemoveSwarmNodes(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RemoveSwarmStacks(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RemoveSwarmServices(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::CreateSwarmConfig(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RotateSwarmConfig(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RemoveSwarmConfigs(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::CreateSwarmSecret(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RotateSwarmSecret(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::RemoveSwarmSecrets(config) => {
config.swarm = resources
.swarms
.get(&config.swarm)
.map(|s| s.name.clone())
.unwrap_or_default();
}
Execution::ClearRepoCache(_) => {}
Execution::BackupCoreDatabase(_) => {}
Execution::GlobalAutoUpdate(_) => {}
Execution::RotateAllServerKeys(_) => {}
Execution::RotateCoreKeys(_) => {}
Execution::Sleep(_) => {}
.iter()
.map(|alerter| {
all
.alerters
.get(alerter)
.map(|a| a.name.clone())
.unwrap_or_default()
})
.collect();
}
// No-op variants
Execution::None(_)
| Execution::BatchRunProcedure(_)
| Execution::BatchRunAction(_)
| Execution::BatchRunBuild(_)
| Execution::BatchDeploy(_)
| Execution::BatchDestroyDeployment(_)
| Execution::BatchCloneRepo(_)
| Execution::BatchPullRepo(_)
| Execution::BatchBuildRepo(_)
| Execution::BatchDeployStack(_)
| Execution::BatchDeployStackIfChanged(_)
| Execution::BatchPullStack(_)
| Execution::BatchDestroyStack(_)
| Execution::ClearRepoCache(_)
| Execution::BackupCoreDatabase(_)
| Execution::GlobalAutoUpdate(_)
| Execution::RotateAllServerKeys(_)
| Execution::RotateCoreKeys(_)
| Execution::Sleep(_) => {}
}
};
}
replace_id_with_name!(
RunProcedure => procedure, procedures;
RunAction => action, actions;
RunBuild => build, builds;
CancelBuild => build, builds;
Deploy => deployment, deployments;
PullDeployment => deployment, deployments;
StartDeployment => deployment, deployments;
RestartDeployment => deployment, deployments;
PauseDeployment => deployment, deployments;
UnpauseDeployment => deployment, deployments;
StopDeployment => deployment, deployments;
DestroyDeployment => deployment, deployments;
CloneRepo => repo, repos;
PullRepo => repo, repos;
BuildRepo => repo, repos;
CancelRepoBuild => repo, repos;
StartContainer => server, servers;
RestartContainer => server, servers;
PauseContainer => server, servers;
UnpauseContainer => server, servers;
StopContainer => server, servers;
DestroyContainer => server, servers;
StartAllContainers => server, servers;
RestartAllContainers => server, servers;
PauseAllContainers => server, servers;
UnpauseAllContainers => server, servers;
StopAllContainers => server, servers;
PruneContainers => server, servers;
DeleteNetwork => server, servers;
PruneNetworks => server, servers;
DeleteImage => server, servers;
PruneImages => server, servers;
DeleteVolume => server, servers;
PruneVolumes => server, servers;
PruneDockerBuilders => server, servers;
PruneBuildx => server, servers;
PruneSystem => server, servers;
RunSync => sync, syncs;
CommitSync => sync, syncs;
DeployStack => stack, stacks;
DeployStackIfChanged => stack, stacks;
PullStack => stack, stacks;
StartStack => stack, stacks;
RestartStack => stack, stacks;
PauseStack => stack, stacks;
UnpauseStack => stack, stacks;
StopStack => stack, stacks;
DestroyStack => stack, stacks;
RunStackService => stack, stacks;
TestAlerter => alerter, alerters;
RemoveSwarmNodes => swarm, swarms;
RemoveSwarmStacks => swarm, swarms;
RemoveSwarmServices => swarm, swarms;
CreateSwarmConfig => swarm, swarms;
RotateSwarmConfig => swarm, swarms;
RemoveSwarmConfigs => swarm, swarms;
CreateSwarmSecret => swarm, swarms;
RotateSwarmSecret => swarm, swarms;
RemoveSwarmSecrets => swarm, swarms;
);
}
}
Ok(original.partial_diff(update))
+8
View File
@@ -178,6 +178,14 @@ impl ToToml for ResourceSync {
impl ToToml for Swarm {
fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
let all = all_resources_cache().load();
resource.config.server_ids.iter_mut().for_each(|server_id| {
*server_id = all
.servers
.get(server_id)
.map(|s| s.name.clone())
.unwrap_or_default();
});
let mut res =
Vec::with_capacity(resource.config.server_ids.capacity());
for server_id in &resource.config.server_ids {
+1 -1
View File
@@ -1,6 +1,6 @@
## All in one, multi stage compile + runtime Docker build for your architecture.
FROM rust:1.93.1-trixie AS builder
FROM rust:1.94.0-trixie AS builder
RUN cargo install cargo-strip
WORKDIR /builder
+1 -1
View File
@@ -2,7 +2,7 @@
## Sets up the necessary runtime container dependencies for Komodo Periphery.
## Since theres no heavy build here, QEMU multi-arch builds are fine for this image.
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:2
ARG X86_64_BINARIES=${BINARIES_IMAGE}-x86_64
ARG AARCH64_BINARIES=${BINARIES_IMAGE}-aarch64
+1 -1
View File
@@ -1,7 +1,7 @@
## Assumes the latest binaries for the required arch are already built (by binaries.Dockerfile).
## Sets up the necessary runtime container dependencies for Komodo Periphery.
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:2
# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries
+219 -44
View File
@@ -307,8 +307,8 @@ impl Resolve<crate::api::Args> for ComposePull {
};
// Canonicalize the path to ensure it exists, and is the cleanest path to the run directory.
let run_directory = run_directory.canonicalize().context(
"Failed to validate run directory on host after stack write (canonicalize error)",
let run_directory = run_directory.canonicalize().with_context(||
format!("Failed to validate run directory on host after stack write (canonicalize error), path={}", run_directory.to_string_lossy()),
)?;
let file_paths = stack
@@ -352,16 +352,56 @@ impl Resolve<crate::api::Args> for ComposePull {
let project_name = stack.project_name(false);
// Parse wrapper configuration
let compose_cmd_wrapper =
parse_multiline_command(&stack.config.compose_cmd_wrapper);
// If wrapper_include is empty but wrapper is set, use default ["up"] for backward compatibility
let default_include = vec![String::from("up")];
let wrapper_include =
if stack.config.compose_cmd_wrapper_include.is_empty()
&& !compose_cmd_wrapper.is_empty()
{
&default_include
} else {
&stack.config.compose_cmd_wrapper_include
};
let pull_command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} pull{service_args}",
);
let (pull_command, wrapped) = match maybe_wrap_command(
pull_command,
&compose_cmd_wrapper,
wrapper_include,
"pull",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
return Ok(res);
}
};
let span = info_span!("RunComposePull");
let log = run_komodo_standard_command(
let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let Some(log) = run_komodo_command_with_sanitization(
"Compose Pull",
run_directory.as_ref(),
format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} pull{service_args}",
),
run_directory.as_path(),
pull_command,
mode,
&replacers,
)
.instrument(span)
.await;
.await
else {
// Only reachable if command is empty,
// not the case since it is provided above.
unreachable!()
};
res.logs.push(log);
@@ -427,8 +467,8 @@ impl Resolve<crate::api::Args> for ComposeUp {
};
// Canonicalize the path to ensure it exists, and is the cleanest path to the run directory.
let run_directory = run_directory.canonicalize().context(
"Failed to validate run directory on host after stack write (canonicalize error)",
let run_directory = run_directory.canonicalize().with_context(||
format!("Failed to validate run directory on host after stack write (canonicalize error), path={}", run_directory.to_string_lossy()),
)?;
validate_files(&stack, &run_directory, &mut res).await;
@@ -483,25 +523,54 @@ impl Resolve<crate::api::Args> for ComposeUp {
&stack.config.additional_env_files,
)?;
// Parse wrapper configuration once for reuse
let compose_cmd_wrapper =
parse_multiline_command(&stack.config.compose_cmd_wrapper);
// If wrapper_include is empty but wrapper is set, use default ["up"] for backward compatibility
let default_include = vec![String::from("up")];
let wrapper_include =
if stack.config.compose_cmd_wrapper_include.is_empty()
&& !compose_cmd_wrapper.is_empty()
{
&default_include
} else {
&stack.config.compose_cmd_wrapper_include
};
// Uses 'docker compose config' command to extract services (including image)
// after performing interpolation
{
let command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} config",
);
let (command, wrapped) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"config",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
return Ok(res);
}
};
let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let span = info_span!("GetComposeConfig", command);
let Some(config_log) = run_komodo_command_with_sanitization(
"Compose Config",
run_directory.as_path(),
command,
KomodoCommandMode::Standard,
mode,
&replacers,
)
.instrument(span)
.await
else {
// Only reachable if command is empty,
// not the case since it is provided above.
unreachable!()
};
if !config_log.success {
@@ -558,12 +627,29 @@ impl Resolve<crate::api::Args> for ComposeUp {
let command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} build{build_extra_args}{service_args}",
);
let (command, wrapped) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"build",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
return Ok(res);
}
};
let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let span = info_span!("ExecuteComposeBuild");
let Some(log) = run_komodo_command_with_sanitization(
"Compose Build",
run_directory.as_path(),
command,
KomodoCommandMode::Shell,
mode,
&replacers,
)
.instrument(span)
@@ -584,14 +670,36 @@ impl Resolve<crate::api::Args> for ComposeUp {
let command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} pull{service_args}",
);
let span = info_span!("RunComposePull");
let log = run_komodo_standard_command(
"Compose Pull",
run_directory.as_ref(),
let (command, wrapped) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"pull",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
return Ok(res);
}
};
let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let span = info_span!("RunComposePull");
let Some(log) = run_komodo_command_with_sanitization(
"Compose Pull",
run_directory.as_path(),
command,
mode,
&replacers,
)
.instrument(span)
.await;
.await
else {
unreachable!()
};
res.logs.push(log);
if !all_logs_success(&res.logs) {
return Ok(res);
@@ -611,24 +719,21 @@ impl Resolve<crate::api::Args> for ComposeUp {
// Run compose up
let extra_args = format_extra_args(&stack.config.extra_args);
let mut command = format!(
let command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} up -d{extra_args}{service_args}",
);
// Apply compose cmd wrapper if configured
let compose_cmd_wrapper =
parse_multiline_command(&stack.config.compose_cmd_wrapper);
if !compose_cmd_wrapper.is_empty() {
if !compose_cmd_wrapper.contains("[[COMPOSE_COMMAND]]") {
res.logs.push(Log::error(
"Compose Command Wrapper",
"compose_cmd_wrapper is configured but does not contain [[COMPOSE_COMMAND]] placeholder. The placeholder is required to inject the compose command.".to_string(),
));
let (command, _) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"up",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
return Ok(res);
}
command =
compose_cmd_wrapper.replace("[[COMPOSE_COMMAND]]", &command);
}
};
let span = info_span!("ExecuteComposeUp");
let Some(log) = run_komodo_command_with_sanitization(
@@ -762,8 +867,8 @@ impl Resolve<crate::api::Args> for ComposeRun {
}
};
let run_directory = run_directory.canonicalize().context(
"Failed to validate run directory on host after stack write (canonicalize error)",
let run_directory = run_directory.canonicalize().with_context(||
format!("Failed to validate run directory on host after stack write (canonicalize error), path={}", run_directory.to_string_lossy())
)?;
maybe_login_registry(&stack, registry_token, &mut Vec::new())
@@ -784,15 +889,49 @@ impl Resolve<crate::api::Args> for ComposeRun {
let project_name = stack.project_name(true);
// Parse wrapper configuration
let compose_cmd_wrapper =
parse_multiline_command(&stack.config.compose_cmd_wrapper);
// If wrapper_include is empty but wrapper is set, use default ["up"] for backward compatibility
let default_include = vec![String::from("up")];
let wrapper_include =
if stack.config.compose_cmd_wrapper_include.is_empty()
&& !compose_cmd_wrapper.is_empty()
{
&default_include
} else {
&stack.config.compose_cmd_wrapper_include
};
if pull.unwrap_or_default() {
let pull_log = run_komodo_standard_command(
let pull_command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} pull {service}",
);
let (pull_command, wrapped) = match maybe_wrap_command(
pull_command,
&compose_cmd_wrapper,
wrapper_include,
"pull",
) {
Ok(result) => result,
Err(log) => return Ok(log),
};
let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let Some(pull_log) = run_komodo_command_with_sanitization(
"Compose Pull",
run_directory.as_ref(),
format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} pull {service}",
),
run_directory.as_path(),
pull_command,
mode,
&replacers,
)
.await;
.await
else {
unreachable!()
};
if !pull_log.success {
return Ok(pull_log);
}
@@ -839,15 +978,24 @@ impl Resolve<crate::api::Args> for ComposeRun {
})
.unwrap_or_default();
let command = format!(
let run_command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} run{run_flags} {service}{command_args}",
);
let (run_command, _) = match maybe_wrap_command(
run_command,
&compose_cmd_wrapper,
wrapper_include,
"run",
) {
Ok(result) => result,
Err(log) => return Ok(log),
};
let span = info_span!("RunComposeRun", command);
let span = info_span!("RunComposeRun", run_command);
let Some(log) = run_komodo_command_with_sanitization(
"Compose Run",
run_directory.as_path(),
command,
run_command,
KomodoCommandMode::Shell,
&replacers,
)
@@ -888,6 +1036,33 @@ fn env_file_args(
Ok(res)
}
/// Apply compose_cmd_wrapper to command if the subcommand is in wrapper_include list.
/// Returns Ok((command, wrapped)) where `wrapped` indicates if wrapper was applied.
/// Returns Err(Log) if wrapper is invalid (missing placeholder).
fn maybe_wrap_command(
command: String,
wrapper: &str,
wrapper_include: &[String],
subcommand: &str,
) -> Result<(String, bool), Log> {
// Skip wrapping if wrapper is empty or subcommand is not in include list
if wrapper.is_empty()
|| !wrapper_include.iter().any(|c| c == subcommand)
{
return Ok((command, false));
}
// Validate wrapper contains placeholder
if !wrapper.contains("[[COMPOSE_COMMAND]]") {
return Err(Log::error(
"Compose Command Wrapper",
"compose_cmd_wrapper is configured but does not contain [[COMPOSE_COMMAND]] placeholder. The placeholder is required to inject the compose command.".to_string(),
));
}
Ok((wrapper.replace("[[COMPOSE_COMMAND]]", &command), true))
}
#[instrument("ComposeDown", skip(res))]
async fn compose_down(
project: &str,
+68 -12
View File
@@ -30,6 +30,32 @@ use crate::{
state::docker_client,
};
/// Apply compose_cmd_wrapper to command if the subcommand is in wrapper_include list.
/// Returns Ok((command, wrapped)) where `wrapped` indicates if wrapper was applied.
fn maybe_wrap_command(
command: String,
wrapper: &str,
wrapper_include: &[String],
subcommand: &str,
) -> Result<(String, bool), Log> {
// Skip wrapping if wrapper is empty or subcommand is not in include list
if wrapper.is_empty()
|| !wrapper_include.iter().any(|c| c == subcommand)
{
return Ok((command, false));
}
// Validate wrapper contains placeholder
if !wrapper.contains("[[COMPOSE_COMMAND]]") {
return Err(Log::error(
"Compose Command Wrapper",
"compose_cmd_wrapper is configured but does not contain [[COMPOSE_COMMAND]] placeholder. The placeholder is required to inject the compose command.".to_string(),
));
}
Ok((wrapper.replace("[[COMPOSE_COMMAND]]", &command), true))
}
impl Resolve<crate::api::Args> for InspectSwarmStack {
async fn resolve(
self,
@@ -178,16 +204,47 @@ impl Resolve<crate::api::Args> for DeploySwarmStack {
let last_project_name = stack.project_name(false);
let project_name = stack.project_name(true);
// Parse wrapper configuration once for reuse
let compose_cmd_wrapper =
parse_multiline_command(&stack.config.compose_cmd_wrapper);
// If wrapper_include is empty but wrapper is set, use default ["deploy"] for backward compatibility
let default_include = vec![String::from("deploy")];
let wrapper_include =
if stack.config.compose_cmd_wrapper_include.is_empty()
&& !compose_cmd_wrapper.is_empty()
{
&default_include
} else {
&stack.config.compose_cmd_wrapper_include
};
// Uses 'docker stack config' command to extract services (including image)
// after performing interpolation
{
let command = format!("docker stack config -c {file_args}",);
let (command, wrapped) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"config",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
return Ok(res);
}
};
let mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let span = info_span!("GetStackConfig", command);
let Some(config_log) = run_komodo_command_with_sanitization(
"Stack Config",
run_directory.as_path(),
command,
KomodoCommandMode::Standard,
mode,
&replacers,
)
.instrument(span)
@@ -240,19 +297,18 @@ impl Resolve<crate::api::Args> for DeploySwarmStack {
write!(&mut command, " {project_name}")?;
// Apply compose cmd wrapper if configured
let compose_cmd_wrapper =
parse_multiline_command(&stack.config.compose_cmd_wrapper);
if !compose_cmd_wrapper.is_empty() {
if !compose_cmd_wrapper.contains("[[COMPOSE_COMMAND]]") {
res.logs.push(Log::error(
"Compose Command Wrapper",
"compose_cmd_wrapper is configured but does not contain [[COMPOSE_COMMAND]] placeholder. The placeholder is required to inject the compose command.".to_string(),
));
let (command, _) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"deploy",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
return Ok(res);
}
command =
compose_cmd_wrapper.replace("[[COMPOSE_COMMAND]]", &command);
}
};
let span = info_span!("ExecuteStackDeploy");
let Some(log) = run_komodo_command_with_sanitization(
+40 -10
View File
@@ -3,7 +3,7 @@ use std::sync::Arc;
use anyhow::{Context, anyhow};
use futures_util::{Stream, StreamExt, TryStreamExt};
use komodo_client::entities::{
KOMODO_EXIT_CODE, NoData,
KOMODO_EXIT_CODE, NoData, optional_string,
terminal::{Terminal, TerminalStdinMessage, TerminalTarget},
};
use mogh_resolver::Resolve;
@@ -52,20 +52,32 @@ impl Resolve<crate::api::Args> for CreateServerTerminal {
async fn resolve(
self,
args: &crate::api::Args,
) -> anyhow::Result<NoData> {
) -> anyhow::Result<Terminal> {
if periphery_config().disable_terminals {
return Err(anyhow!(
"Terminals are disabled in the Periphery config"
));
}
let existing =
list_terminals(Some(&TerminalTarget::Server { server: None }))
.await;
create_terminal(
self.name,
self
.name
.and_then(optional_string)
.unwrap_or_else(|| format!("term-{}", existing.len())),
TerminalTarget::Server { server: None },
self.command,
self.recreate,
)
.await
.map(|_| NoData {})
.map(|terminal| Terminal {
name: terminal.name.clone(),
target: TerminalTarget::Server { server: None },
command: terminal.command.clone(),
stored_size_kb: terminal.history.size_kb(),
created_at: terminal.created_at,
})
}
}
@@ -87,7 +99,7 @@ impl Resolve<crate::api::Args> for CreateContainerExecTerminal {
async fn resolve(
self,
args: &crate::api::Args,
) -> anyhow::Result<NoData> {
) -> anyhow::Result<Terminal> {
if periphery_config().disable_container_terminals {
return Err(anyhow!(
"Container Terminals are disabled in the Periphery config"
@@ -106,14 +118,23 @@ impl Resolve<crate::api::Args> for CreateContainerExecTerminal {
"The use of '&&' is forbidden in the container name or command"
));
}
let existing = list_terminals(Some(&target)).await;
create_terminal(
name,
name.and_then(optional_string).unwrap_or_else(|| {
format!("exec-{container}-{}", existing.len())
}),
target,
Some(format!("docker exec -it {container} {command}")),
recreate,
)
.await
.map(|_| NoData {})
.map(|terminal| Terminal {
name: terminal.name.clone(),
target: terminal.target.clone(),
command: terminal.command.clone(),
stored_size_kb: terminal.history.size_kb(),
created_at: terminal.created_at,
})
}
}
@@ -134,7 +155,7 @@ impl Resolve<crate::api::Args> for CreateContainerAttachTerminal {
async fn resolve(
self,
args: &crate::api::Args,
) -> anyhow::Result<NoData> {
) -> anyhow::Result<Terminal> {
if periphery_config().disable_container_terminals {
return Err(anyhow!(
"Container Terminals are disabled in the Periphery config"
@@ -151,14 +172,23 @@ impl Resolve<crate::api::Args> for CreateContainerAttachTerminal {
"The use of '&&' is forbidden in the container name"
));
}
let existing = list_terminals(Some(&target)).await;
create_terminal(
name,
name.and_then(optional_string).unwrap_or_else(|| {
format!("attach-{container}-{}", existing.len())
}),
target,
Some(format!("docker attach {container} --sig-proxy=false")),
recreate,
)
.await
.map(|_| NoData {})
.map(|terminal| Terminal {
name: terminal.name.clone(),
target: terminal.target.clone(),
command: terminal.command.clone(),
stored_size_kb: terminal.history.size_kb(),
created_at: terminal.created_at,
})
}
}
+7
View File
@@ -94,6 +94,13 @@ pub async fn handler(
already_logged_connection_error = false;
debug!(
host = identifiers.host(),
query,
sec_websocket_accept = accept.to_str().unwrap_or_default(),
"[CORE AUTH] Zero trust identifiers"
);
let identifiers =
identifiers.build(accept.as_bytes(), query.as_bytes());
+7
View File
@@ -109,6 +109,13 @@ async fn handler(
let query = format!("core={}", urlencoding::encode(&core));
debug!(
host = identifiers.host.to_str().unwrap_or_default(),
query,
sec_websocket_accept = identifiers.accept,
"[CORE AUTH] Zero trust identifiers"
);
if let Err(e) =
handle_login(&mut socket, identifiers.build(query.as_bytes()))
.await
+46 -46
View File
@@ -461,80 +461,80 @@ impl DockerClient {
}
fn convert_summary_container_state(
state: bollard::secret::ContainerSummaryStateEnum,
state: bollard::config::ContainerSummaryStateEnum,
) -> ContainerStateStatusEnum {
match state {
bollard::secret::ContainerSummaryStateEnum::EMPTY => {
bollard::config::ContainerSummaryStateEnum::EMPTY => {
ContainerStateStatusEnum::Empty
}
bollard::secret::ContainerSummaryStateEnum::CREATED => {
bollard::config::ContainerSummaryStateEnum::CREATED => {
ContainerStateStatusEnum::Created
}
bollard::secret::ContainerSummaryStateEnum::RUNNING => {
bollard::config::ContainerSummaryStateEnum::RUNNING => {
ContainerStateStatusEnum::Running
}
bollard::secret::ContainerSummaryStateEnum::PAUSED => {
bollard::config::ContainerSummaryStateEnum::PAUSED => {
ContainerStateStatusEnum::Paused
}
bollard::secret::ContainerSummaryStateEnum::RESTARTING => {
bollard::config::ContainerSummaryStateEnum::RESTARTING => {
ContainerStateStatusEnum::Restarting
}
bollard::secret::ContainerSummaryStateEnum::EXITED => {
bollard::config::ContainerSummaryStateEnum::EXITED => {
ContainerStateStatusEnum::Exited
}
bollard::secret::ContainerSummaryStateEnum::REMOVING => {
bollard::config::ContainerSummaryStateEnum::REMOVING => {
ContainerStateStatusEnum::Removing
}
bollard::secret::ContainerSummaryStateEnum::DEAD => {
bollard::config::ContainerSummaryStateEnum::DEAD => {
ContainerStateStatusEnum::Dead
}
}
}
fn convert_container_state_status(
state: bollard::secret::ContainerStateStatusEnum,
state: bollard::config::ContainerStateStatusEnum,
) -> ContainerStateStatusEnum {
match state {
bollard::secret::ContainerStateStatusEnum::EMPTY => {
bollard::config::ContainerStateStatusEnum::EMPTY => {
ContainerStateStatusEnum::Empty
}
bollard::secret::ContainerStateStatusEnum::CREATED => {
bollard::config::ContainerStateStatusEnum::CREATED => {
ContainerStateStatusEnum::Created
}
bollard::secret::ContainerStateStatusEnum::RUNNING => {
bollard::config::ContainerStateStatusEnum::RUNNING => {
ContainerStateStatusEnum::Running
}
bollard::secret::ContainerStateStatusEnum::PAUSED => {
bollard::config::ContainerStateStatusEnum::PAUSED => {
ContainerStateStatusEnum::Paused
}
bollard::secret::ContainerStateStatusEnum::RESTARTING => {
bollard::config::ContainerStateStatusEnum::RESTARTING => {
ContainerStateStatusEnum::Restarting
}
bollard::secret::ContainerStateStatusEnum::EXITED => {
bollard::config::ContainerStateStatusEnum::EXITED => {
ContainerStateStatusEnum::Exited
}
bollard::secret::ContainerStateStatusEnum::REMOVING => {
bollard::config::ContainerStateStatusEnum::REMOVING => {
ContainerStateStatusEnum::Removing
}
bollard::secret::ContainerStateStatusEnum::DEAD => {
bollard::config::ContainerStateStatusEnum::DEAD => {
ContainerStateStatusEnum::Dead
}
}
}
fn convert_port_type(
typ: bollard::secret::PortSummaryTypeEnum,
typ: bollard::config::PortSummaryTypeEnum,
) -> PortTypeEnum {
match typ {
bollard::secret::PortSummaryTypeEnum::EMPTY => {
bollard::config::PortSummaryTypeEnum::EMPTY => {
PortTypeEnum::EMPTY
}
bollard::secret::PortSummaryTypeEnum::TCP => PortTypeEnum::TCP,
bollard::secret::PortSummaryTypeEnum::UDP => PortTypeEnum::UDP,
bollard::secret::PortSummaryTypeEnum::SCTP => PortTypeEnum::SCTP,
bollard::config::PortSummaryTypeEnum::TCP => PortTypeEnum::TCP,
bollard::config::PortSummaryTypeEnum::UDP => PortTypeEnum::UDP,
bollard::config::PortSummaryTypeEnum::SCTP => PortTypeEnum::SCTP,
}
}
fn convert_port(port: bollard::secret::PortSummary) -> Port {
fn convert_port(port: bollard::config::PortSummary) -> Port {
Port {
ip: port.ip,
private_port: port.private_port,
@@ -544,27 +544,27 @@ fn convert_port(port: bollard::secret::PortSummary) -> Port {
}
fn convert_health_status(
status: bollard::secret::HealthStatusEnum,
status: bollard::config::HealthStatusEnum,
) -> HealthStatusEnum {
match status {
bollard::secret::HealthStatusEnum::EMPTY => {
bollard::config::HealthStatusEnum::EMPTY => {
HealthStatusEnum::Empty
}
bollard::secret::HealthStatusEnum::NONE => HealthStatusEnum::None,
bollard::secret::HealthStatusEnum::STARTING => {
bollard::config::HealthStatusEnum::NONE => HealthStatusEnum::None,
bollard::config::HealthStatusEnum::STARTING => {
HealthStatusEnum::Starting
}
bollard::secret::HealthStatusEnum::HEALTHY => {
bollard::config::HealthStatusEnum::HEALTHY => {
HealthStatusEnum::Healthy
}
bollard::secret::HealthStatusEnum::UNHEALTHY => {
bollard::config::HealthStatusEnum::UNHEALTHY => {
HealthStatusEnum::Unhealthy
}
}
}
fn convert_health_check_result(
check: bollard::secret::HealthcheckResult,
check: bollard::config::HealthcheckResult,
) -> HealthcheckResult {
HealthcheckResult {
start: check.start,
@@ -575,57 +575,57 @@ fn convert_health_check_result(
}
fn convert_restart_policy(
policy: bollard::secret::RestartPolicyNameEnum,
policy: bollard::config::RestartPolicyNameEnum,
) -> RestartPolicyNameEnum {
match policy {
bollard::secret::RestartPolicyNameEnum::EMPTY => {
bollard::config::RestartPolicyNameEnum::EMPTY => {
RestartPolicyNameEnum::Empty
}
bollard::secret::RestartPolicyNameEnum::NO => {
bollard::config::RestartPolicyNameEnum::NO => {
RestartPolicyNameEnum::No
}
bollard::secret::RestartPolicyNameEnum::ALWAYS => {
bollard::config::RestartPolicyNameEnum::ALWAYS => {
RestartPolicyNameEnum::Always
}
bollard::secret::RestartPolicyNameEnum::UNLESS_STOPPED => {
bollard::config::RestartPolicyNameEnum::UNLESS_STOPPED => {
RestartPolicyNameEnum::UnlessStopped
}
bollard::secret::RestartPolicyNameEnum::ON_FAILURE => {
bollard::config::RestartPolicyNameEnum::ON_FAILURE => {
RestartPolicyNameEnum::OnFailure
}
}
}
fn convert_cgroupns_mode(
mode: bollard::secret::HostConfigCgroupnsModeEnum,
mode: bollard::config::HostConfigCgroupnsModeEnum,
) -> HostConfigCgroupnsModeEnum {
match mode {
bollard::secret::HostConfigCgroupnsModeEnum::EMPTY => {
bollard::config::HostConfigCgroupnsModeEnum::EMPTY => {
HostConfigCgroupnsModeEnum::Empty
}
bollard::secret::HostConfigCgroupnsModeEnum::PRIVATE => {
bollard::config::HostConfigCgroupnsModeEnum::PRIVATE => {
HostConfigCgroupnsModeEnum::Private
}
bollard::secret::HostConfigCgroupnsModeEnum::HOST => {
bollard::config::HostConfigCgroupnsModeEnum::HOST => {
HostConfigCgroupnsModeEnum::Host
}
}
}
fn convert_isolation_mode(
isolation: bollard::secret::HostConfigIsolationEnum,
isolation: bollard::config::HostConfigIsolationEnum,
) -> HostConfigIsolationEnum {
match isolation {
bollard::secret::HostConfigIsolationEnum::EMPTY => {
bollard::config::HostConfigIsolationEnum::EMPTY => {
HostConfigIsolationEnum::Empty
}
bollard::secret::HostConfigIsolationEnum::DEFAULT => {
bollard::config::HostConfigIsolationEnum::DEFAULT => {
HostConfigIsolationEnum::Default
}
bollard::secret::HostConfigIsolationEnum::PROCESS => {
bollard::config::HostConfigIsolationEnum::PROCESS => {
HostConfigIsolationEnum::Process
}
bollard::secret::HostConfigIsolationEnum::HYPERV => {
bollard::config::HostConfigIsolationEnum::HYPERV => {
HostConfigIsolationEnum::Hyperv
}
}
+7 -8
View File
@@ -29,8 +29,7 @@ impl DockerClient {
});
let name = image
.repo_tags
.iter()
.next()
.first()
.cloned()
.unwrap_or_else(|| image.id.clone());
ImageListItem {
@@ -73,10 +72,10 @@ impl DockerClient {
content: manifest.size.content,
},
kind: manifest.kind.map(|kind| match kind {
bollard::secret::ImageManifestSummaryKindEnum::EMPTY => ImageManifestSummaryKindEnum::Empty,
bollard::secret::ImageManifestSummaryKindEnum::IMAGE => ImageManifestSummaryKindEnum::Image,
bollard::secret::ImageManifestSummaryKindEnum::ATTESTATION => ImageManifestSummaryKindEnum::Attestation,
bollard::secret::ImageManifestSummaryKindEnum::UNKNOWN => ImageManifestSummaryKindEnum::Unknown,
bollard::config::ImageManifestSummaryKindEnum::EMPTY => ImageManifestSummaryKindEnum::Empty,
bollard::config::ImageManifestSummaryKindEnum::IMAGE => ImageManifestSummaryKindEnum::Image,
bollard::config::ImageManifestSummaryKindEnum::ATTESTATION => ImageManifestSummaryKindEnum::Attestation,
bollard::config::ImageManifestSummaryKindEnum::UNKNOWN => ImageManifestSummaryKindEnum::Unknown,
}),
image_data: manifest.image_data.map(|data| {
ImageManifestSummaryImageData {
@@ -160,7 +159,7 @@ impl DockerClient {
}
fn convert_oci_descriptor(
descriptor: bollard::secret::OciDescriptor,
descriptor: bollard::config::OciDescriptor,
) -> OciDescriptor {
OciDescriptor {
media_type: descriptor.media_type,
@@ -175,7 +174,7 @@ fn convert_oci_descriptor(
}
fn convert_oci_platform(
platform: bollard::secret::OciPlatform,
platform: bollard::config::OciPlatform,
) -> OciPlatform {
OciPlatform {
architecture: platform.architecture,
+47 -47
View File
@@ -151,68 +151,68 @@ fn convert_mount(mount: bollard::models::Mount) -> Mount {
}
fn convert_mount_type(
typ: bollard::secret::MountTypeEnum,
typ: bollard::config::MountTypeEnum,
) -> MountTypeEnum {
match typ {
bollard::secret::MountTypeEnum::EMPTY => MountTypeEnum::Empty,
bollard::secret::MountTypeEnum::BIND => MountTypeEnum::Bind,
bollard::secret::MountTypeEnum::VOLUME => MountTypeEnum::Volume,
bollard::secret::MountTypeEnum::IMAGE => MountTypeEnum::Image,
bollard::secret::MountTypeEnum::TMPFS => MountTypeEnum::Tmpfs,
bollard::secret::MountTypeEnum::NPIPE => MountTypeEnum::Npipe,
bollard::secret::MountTypeEnum::CLUSTER => MountTypeEnum::Cluster,
bollard::config::MountTypeEnum::EMPTY => MountTypeEnum::Empty,
bollard::config::MountTypeEnum::BIND => MountTypeEnum::Bind,
bollard::config::MountTypeEnum::VOLUME => MountTypeEnum::Volume,
bollard::config::MountTypeEnum::IMAGE => MountTypeEnum::Image,
bollard::config::MountTypeEnum::TMPFS => MountTypeEnum::Tmpfs,
bollard::config::MountTypeEnum::NPIPE => MountTypeEnum::Npipe,
bollard::config::MountTypeEnum::CLUSTER => MountTypeEnum::Cluster,
}
}
fn convert_mount_propogation(
propogation: bollard::secret::MountBindOptionsPropagationEnum,
propogation: bollard::config::MountBindOptionsPropagationEnum,
) -> MountBindOptionsPropagationEnum {
match propogation {
bollard::secret::MountBindOptionsPropagationEnum::EMPTY => {
bollard::config::MountBindOptionsPropagationEnum::EMPTY => {
MountBindOptionsPropagationEnum::Empty
}
bollard::secret::MountBindOptionsPropagationEnum::PRIVATE => {
bollard::config::MountBindOptionsPropagationEnum::PRIVATE => {
MountBindOptionsPropagationEnum::Private
}
bollard::secret::MountBindOptionsPropagationEnum::RPRIVATE => {
bollard::config::MountBindOptionsPropagationEnum::RPRIVATE => {
MountBindOptionsPropagationEnum::Rprivate
}
bollard::secret::MountBindOptionsPropagationEnum::SHARED => {
bollard::config::MountBindOptionsPropagationEnum::SHARED => {
MountBindOptionsPropagationEnum::Shared
}
bollard::secret::MountBindOptionsPropagationEnum::RSHARED => {
bollard::config::MountBindOptionsPropagationEnum::RSHARED => {
MountBindOptionsPropagationEnum::Rshared
}
bollard::secret::MountBindOptionsPropagationEnum::SLAVE => {
bollard::config::MountBindOptionsPropagationEnum::SLAVE => {
MountBindOptionsPropagationEnum::Slave
}
bollard::secret::MountBindOptionsPropagationEnum::RSLAVE => {
bollard::config::MountBindOptionsPropagationEnum::RSLAVE => {
MountBindOptionsPropagationEnum::Rslave
}
}
}
fn convert_mount_point_type(
typ: bollard::secret::MountPointTypeEnum,
typ: bollard::config::MountPointTypeEnum,
) -> MountTypeEnum {
match typ {
bollard::secret::MountPointTypeEnum::EMPTY => {
bollard::config::MountPointTypeEnum::EMPTY => {
MountTypeEnum::Empty
}
bollard::secret::MountPointTypeEnum::BIND => MountTypeEnum::Bind,
bollard::secret::MountPointTypeEnum::VOLUME => {
bollard::config::MountPointTypeEnum::BIND => MountTypeEnum::Bind,
bollard::config::MountPointTypeEnum::VOLUME => {
MountTypeEnum::Volume
}
bollard::secret::MountPointTypeEnum::IMAGE => {
bollard::config::MountPointTypeEnum::IMAGE => {
MountTypeEnum::Image
}
bollard::secret::MountPointTypeEnum::TMPFS => {
bollard::config::MountPointTypeEnum::TMPFS => {
MountTypeEnum::Tmpfs
}
bollard::secret::MountPointTypeEnum::NPIPE => {
bollard::config::MountPointTypeEnum::NPIPE => {
MountTypeEnum::Npipe
}
bollard::secret::MountPointTypeEnum::CLUSTER => {
bollard::config::MountPointTypeEnum::CLUSTER => {
MountTypeEnum::Cluster
}
}
@@ -290,17 +290,17 @@ fn convert_endpoint_spec_ports(
.map(|port| EndpointPortConfig {
name: port.name,
protocol: port.protocol.map(|protocol| match protocol {
bollard::secret::EndpointPortConfigProtocolEnum::EMPTY => EndpointPortConfigProtocolEnum::EMPTY,
bollard::secret::EndpointPortConfigProtocolEnum::TCP => EndpointPortConfigProtocolEnum::TCP,
bollard::secret::EndpointPortConfigProtocolEnum::UDP => EndpointPortConfigProtocolEnum::UDP,
bollard::secret::EndpointPortConfigProtocolEnum::SCTP => EndpointPortConfigProtocolEnum::SCTP,
bollard::config::EndpointPortConfigProtocolEnum::EMPTY => EndpointPortConfigProtocolEnum::EMPTY,
bollard::config::EndpointPortConfigProtocolEnum::TCP => EndpointPortConfigProtocolEnum::TCP,
bollard::config::EndpointPortConfigProtocolEnum::UDP => EndpointPortConfigProtocolEnum::UDP,
bollard::config::EndpointPortConfigProtocolEnum::SCTP => EndpointPortConfigProtocolEnum::SCTP,
}),
target_port: port.target_port,
published_port: port.published_port,
publish_mode: port.publish_mode.map(|protocol| match protocol {
bollard::secret::EndpointPortConfigPublishModeEnum::EMPTY => EndpointPortConfigPublishModeEnum::EMPTY,
bollard::secret::EndpointPortConfigPublishModeEnum::INGRESS => EndpointPortConfigPublishModeEnum::INGRESS,
bollard::secret::EndpointPortConfigPublishModeEnum::HOST => EndpointPortConfigPublishModeEnum::HOST,
bollard::config::EndpointPortConfigPublishModeEnum::EMPTY => EndpointPortConfigPublishModeEnum::EMPTY,
bollard::config::EndpointPortConfigPublishModeEnum::INGRESS => EndpointPortConfigPublishModeEnum::INGRESS,
bollard::config::EndpointPortConfigPublishModeEnum::HOST => EndpointPortConfigPublishModeEnum::HOST,
}),
})
.collect()
@@ -423,10 +423,10 @@ fn convert_task_spec_container_spec(
seccomp: privilege.seccomp.map(|seccomp| {
TaskSpecContainerSpecPrivilegesSeccomp {
mode: seccomp.mode.map(|mode| match mode {
bollard::secret::TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY,
bollard::secret::TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT,
bollard::secret::TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED => TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED,
bollard::secret::TaskSpecContainerSpecPrivilegesSeccompModeEnum::CUSTOM => TaskSpecContainerSpecPrivilegesSeccompModeEnum::CUSTOM,
bollard::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY,
bollard::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT,
bollard::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED => TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED,
bollard::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::CUSTOM => TaskSpecContainerSpecPrivilegesSeccompModeEnum::CUSTOM,
}),
profile: seccomp.profile,
}
@@ -434,9 +434,9 @@ fn convert_task_spec_container_spec(
app_armor: privilege.app_armor.map(|app_armor| {
TaskSpecContainerSpecPrivilegesAppArmor {
mode: app_armor.mode.map(|mode| match mode {
bollard::secret::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY,
bollard::secret::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT,
bollard::secret::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DISABLED => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DISABLED,
bollard::config::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY,
bollard::config::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT,
bollard::config::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DISABLED => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DISABLED,
}),
}
}),
@@ -478,10 +478,10 @@ fn convert_task_spec_container_spec(
config_name: config.config_name,
}).collect()),
isolation: spec.isolation.map(|isolation| match isolation {
bollard::secret::TaskSpecContainerSpecIsolationEnum::DEFAULT => TaskSpecContainerSpecIsolationEnum::DEFAULT,
bollard::secret::TaskSpecContainerSpecIsolationEnum::PROCESS => TaskSpecContainerSpecIsolationEnum::PROCESS,
bollard::secret::TaskSpecContainerSpecIsolationEnum::HYPERV => TaskSpecContainerSpecIsolationEnum::HYPERV,
bollard::secret::TaskSpecContainerSpecIsolationEnum::EMPTY => TaskSpecContainerSpecIsolationEnum::EMPTY,
bollard::config::TaskSpecContainerSpecIsolationEnum::DEFAULT => TaskSpecContainerSpecIsolationEnum::DEFAULT,
bollard::config::TaskSpecContainerSpecIsolationEnum::PROCESS => TaskSpecContainerSpecIsolationEnum::PROCESS,
bollard::config::TaskSpecContainerSpecIsolationEnum::HYPERV => TaskSpecContainerSpecIsolationEnum::HYPERV,
bollard::config::TaskSpecContainerSpecIsolationEnum::EMPTY => TaskSpecContainerSpecIsolationEnum::EMPTY,
}),
init: spec.init,
sysctls: spec.sysctls,
@@ -492,13 +492,13 @@ fn convert_task_spec_container_spec(
}
fn convert_task_spec_restart_policy_condition(
condition: bollard::secret::TaskSpecRestartPolicyConditionEnum,
condition: bollard::config::TaskSpecRestartPolicyConditionEnum,
) -> TaskSpecRestartPolicyConditionEnum {
match condition {
bollard::secret::TaskSpecRestartPolicyConditionEnum::EMPTY => TaskSpecRestartPolicyConditionEnum::EMPTY,
bollard::secret::TaskSpecRestartPolicyConditionEnum::NONE => TaskSpecRestartPolicyConditionEnum::NONE,
bollard::secret::TaskSpecRestartPolicyConditionEnum::ON_FAILURE => TaskSpecRestartPolicyConditionEnum::ON_FAILURE,
bollard::secret::TaskSpecRestartPolicyConditionEnum::ANY => TaskSpecRestartPolicyConditionEnum::ANY,
bollard::config::TaskSpecRestartPolicyConditionEnum::EMPTY => TaskSpecRestartPolicyConditionEnum::EMPTY,
bollard::config::TaskSpecRestartPolicyConditionEnum::NONE => TaskSpecRestartPolicyConditionEnum::NONE,
bollard::config::TaskSpecRestartPolicyConditionEnum::ON_FAILURE => TaskSpecRestartPolicyConditionEnum::ON_FAILURE,
bollard::config::TaskSpecRestartPolicyConditionEnum::ANY => TaskSpecRestartPolicyConditionEnum::ANY,
}
}
+17 -17
View File
@@ -116,13 +116,13 @@ fn convert_node(node: bollard::models::Node) -> SwarmNode {
leader: manager_status.leader,
reachability: manager_status.reachability.map(
|reachability| match reachability {
bollard::secret::Reachability::UNKNOWN => {
bollard::config::Reachability::UNKNOWN => {
NodeReachability::UNKNOWN
}
bollard::secret::Reachability::UNREACHABLE => {
bollard::config::Reachability::UNREACHABLE => {
NodeReachability::UNREACHABLE
}
bollard::secret::Reachability::REACHABLE => {
bollard::config::Reachability::REACHABLE => {
NodeReachability::REACHABLE
}
},
@@ -143,46 +143,46 @@ fn convert_node_spec(spec: bollard::models::NodeSpec) -> NodeSpec {
}
fn convert_role(
role: bollard::secret::NodeSpecRoleEnum,
role: bollard::config::NodeSpecRoleEnum,
) -> NodeSpecRoleEnum {
match role {
bollard::secret::NodeSpecRoleEnum::EMPTY => {
bollard::config::NodeSpecRoleEnum::EMPTY => {
NodeSpecRoleEnum::EMPTY
}
bollard::secret::NodeSpecRoleEnum::WORKER => {
bollard::config::NodeSpecRoleEnum::WORKER => {
NodeSpecRoleEnum::WORKER
}
bollard::secret::NodeSpecRoleEnum::MANAGER => {
bollard::config::NodeSpecRoleEnum::MANAGER => {
NodeSpecRoleEnum::MANAGER
}
}
}
fn convert_availability(
availability: bollard::secret::NodeSpecAvailabilityEnum,
availability: bollard::config::NodeSpecAvailabilityEnum,
) -> NodeSpecAvailabilityEnum {
match availability {
bollard::secret::NodeSpecAvailabilityEnum::EMPTY => {
bollard::config::NodeSpecAvailabilityEnum::EMPTY => {
NodeSpecAvailabilityEnum::EMPTY
}
bollard::secret::NodeSpecAvailabilityEnum::ACTIVE => {
bollard::config::NodeSpecAvailabilityEnum::ACTIVE => {
NodeSpecAvailabilityEnum::ACTIVE
}
bollard::secret::NodeSpecAvailabilityEnum::PAUSE => {
bollard::config::NodeSpecAvailabilityEnum::PAUSE => {
NodeSpecAvailabilityEnum::PAUSE
}
bollard::secret::NodeSpecAvailabilityEnum::DRAIN => {
bollard::config::NodeSpecAvailabilityEnum::DRAIN => {
NodeSpecAvailabilityEnum::DRAIN
}
}
}
fn convert_state(state: bollard::secret::NodeState) -> NodeState {
fn convert_state(state: bollard::config::NodeState) -> NodeState {
match state {
bollard::secret::NodeState::UNKNOWN => NodeState::UNKNOWN,
bollard::secret::NodeState::DOWN => NodeState::DOWN,
bollard::secret::NodeState::READY => NodeState::READY,
bollard::secret::NodeState::DISCONNECTED => {
bollard::config::NodeState::UNKNOWN => NodeState::UNKNOWN,
bollard::config::NodeState::DOWN => NodeState::DOWN,
bollard::config::NodeState::READY => NodeState::READY,
bollard::config::NodeState::DISCONNECTED => {
NodeState::DISCONNECTED
}
}
+25 -25
View File
@@ -27,7 +27,7 @@ impl DockerClient {
.await
.context("Failed to query for swarm service list")?
.into_iter()
.map(|service| convert_service_list_item(service))
.map(convert_service_list_item)
.collect::<Vec<_>>();
services.sort_by(|a, b| {
@@ -324,17 +324,17 @@ fn convert_service(
parallelism: config.parallelism,
delay: config.delay,
failure_action: config.failure_action.map(|action| match action {
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::EMPTY => ServiceSpecUpdateConfigFailureActionEnum::EMPTY,
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::CONTINUE => ServiceSpecUpdateConfigFailureActionEnum::CONTINUE,
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::PAUSE => ServiceSpecUpdateConfigFailureActionEnum::PAUSE,
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK => ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK,
bollard::config::ServiceSpecUpdateConfigFailureActionEnum::EMPTY => ServiceSpecUpdateConfigFailureActionEnum::EMPTY,
bollard::config::ServiceSpecUpdateConfigFailureActionEnum::CONTINUE => ServiceSpecUpdateConfigFailureActionEnum::CONTINUE,
bollard::config::ServiceSpecUpdateConfigFailureActionEnum::PAUSE => ServiceSpecUpdateConfigFailureActionEnum::PAUSE,
bollard::config::ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK => ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK,
}),
monitor: config.monitor,
max_failure_ratio: config.max_failure_ratio,
order: config.order.map(|order| match order {
bollard::secret::ServiceSpecUpdateConfigOrderEnum::EMPTY => ServiceSpecUpdateConfigOrderEnum::EMPTY,
bollard::secret::ServiceSpecUpdateConfigOrderEnum::STOP_FIRST => ServiceSpecUpdateConfigOrderEnum::STOP_FIRST,
bollard::secret::ServiceSpecUpdateConfigOrderEnum::START_FIRST => ServiceSpecUpdateConfigOrderEnum::START_FIRST,
bollard::config::ServiceSpecUpdateConfigOrderEnum::EMPTY => ServiceSpecUpdateConfigOrderEnum::EMPTY,
bollard::config::ServiceSpecUpdateConfigOrderEnum::STOP_FIRST => ServiceSpecUpdateConfigOrderEnum::STOP_FIRST,
bollard::config::ServiceSpecUpdateConfigOrderEnum::START_FIRST => ServiceSpecUpdateConfigOrderEnum::START_FIRST,
}),
}
}),
@@ -343,16 +343,16 @@ fn convert_service(
parallelism: config.parallelism,
delay: config.delay,
failure_action: config.failure_action.map(|action| match action {
bollard::secret::ServiceSpecRollbackConfigFailureActionEnum::EMPTY => ServiceSpecRollbackConfigFailureActionEnum::EMPTY,
bollard::secret::ServiceSpecRollbackConfigFailureActionEnum::CONTINUE => ServiceSpecRollbackConfigFailureActionEnum::CONTINUE,
bollard::secret::ServiceSpecRollbackConfigFailureActionEnum::PAUSE => ServiceSpecRollbackConfigFailureActionEnum::PAUSE,
bollard::config::ServiceSpecRollbackConfigFailureActionEnum::EMPTY => ServiceSpecRollbackConfigFailureActionEnum::EMPTY,
bollard::config::ServiceSpecRollbackConfigFailureActionEnum::CONTINUE => ServiceSpecRollbackConfigFailureActionEnum::CONTINUE,
bollard::config::ServiceSpecRollbackConfigFailureActionEnum::PAUSE => ServiceSpecRollbackConfigFailureActionEnum::PAUSE,
}),
monitor: config.monitor,
max_failure_ratio: config.max_failure_ratio,
order: config.order.map(|order| match order {
bollard::secret::ServiceSpecRollbackConfigOrderEnum::EMPTY => ServiceSpecRollbackConfigOrderEnum::EMPTY,
bollard::secret::ServiceSpecRollbackConfigOrderEnum::STOP_FIRST => ServiceSpecRollbackConfigOrderEnum::STOP_FIRST,
bollard::secret::ServiceSpecRollbackConfigOrderEnum::START_FIRST => ServiceSpecRollbackConfigOrderEnum::START_FIRST,
bollard::config::ServiceSpecRollbackConfigOrderEnum::EMPTY => ServiceSpecRollbackConfigOrderEnum::EMPTY,
bollard::config::ServiceSpecRollbackConfigOrderEnum::STOP_FIRST => ServiceSpecRollbackConfigOrderEnum::STOP_FIRST,
bollard::config::ServiceSpecRollbackConfigOrderEnum::START_FIRST => ServiceSpecRollbackConfigOrderEnum::START_FIRST,
}),
}
}),
@@ -408,13 +408,13 @@ fn convert_endpoint_spec(
) -> EndpointSpec {
EndpointSpec {
mode: spec.mode.map(|mode| match mode {
bollard::secret::EndpointSpecModeEnum::EMPTY => {
bollard::config::EndpointSpecModeEnum::EMPTY => {
EndpointSpecModeEnum::EMPTY
}
bollard::secret::EndpointSpecModeEnum::VIP => {
bollard::config::EndpointSpecModeEnum::VIP => {
EndpointSpecModeEnum::VIP
}
bollard::secret::EndpointSpecModeEnum::DNSRR => {
bollard::config::EndpointSpecModeEnum::DNSRR => {
EndpointSpecModeEnum::DNSRR
}
}),
@@ -423,15 +423,15 @@ fn convert_endpoint_spec(
}
fn convert_state(
state: bollard::secret::ServiceUpdateStatusStateEnum,
state: bollard::config::ServiceUpdateStatusStateEnum,
) -> ServiceUpdateStatusStateEnum {
match state {
bollard::secret::ServiceUpdateStatusStateEnum::EMPTY => ServiceUpdateStatusStateEnum::EMPTY,
bollard::secret::ServiceUpdateStatusStateEnum::UPDATING => ServiceUpdateStatusStateEnum::UPDATING,
bollard::secret::ServiceUpdateStatusStateEnum::PAUSED => ServiceUpdateStatusStateEnum::PAUSED,
bollard::secret::ServiceUpdateStatusStateEnum::COMPLETED => ServiceUpdateStatusStateEnum::COMPLETED,
bollard::secret::ServiceUpdateStatusStateEnum::ROLLBACK_STARTED => ServiceUpdateStatusStateEnum::ROLLBACK_STARTED,
bollard::secret::ServiceUpdateStatusStateEnum::ROLLBACK_PAUSED => ServiceUpdateStatusStateEnum::ROLLBACK_PAUSED,
bollard::secret::ServiceUpdateStatusStateEnum::ROLLBACK_COMPLETED => ServiceUpdateStatusStateEnum::ROLLBACK_COMPLETED,
bollard::config::ServiceUpdateStatusStateEnum::EMPTY => ServiceUpdateStatusStateEnum::EMPTY,
bollard::config::ServiceUpdateStatusStateEnum::UPDATING => ServiceUpdateStatusStateEnum::UPDATING,
bollard::config::ServiceUpdateStatusStateEnum::PAUSED => ServiceUpdateStatusStateEnum::PAUSED,
bollard::config::ServiceUpdateStatusStateEnum::COMPLETED => ServiceUpdateStatusStateEnum::COMPLETED,
bollard::config::ServiceUpdateStatusStateEnum::ROLLBACK_STARTED => ServiceUpdateStatusStateEnum::ROLLBACK_STARTED,
bollard::config::ServiceUpdateStatusStateEnum::ROLLBACK_PAUSED => ServiceUpdateStatusStateEnum::ROLLBACK_PAUSED,
bollard::config::ServiceUpdateStatusStateEnum::ROLLBACK_COMPLETED => ServiceUpdateStatusStateEnum::ROLLBACK_COMPLETED,
}
}
+2 -2
View File
@@ -60,8 +60,8 @@ fn convert_swarm_info(
.into_iter()
.map(|cas| SwarmSpecCaConfigExternalCas {
protocol: cas.protocol.map(|protocol| match protocol {
bollard::secret::SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY => SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY,
bollard::secret::SwarmSpecCaConfigExternalCasProtocolEnum::CFSSL => SwarmSpecCaConfigExternalCasProtocolEnum::CFSSL,
bollard::config::SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY => SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY,
bollard::config::SwarmSpecCaConfigExternalCasProtocolEnum::CFSSL => SwarmSpecCaConfigExternalCasProtocolEnum::CFSSL,
}),
url: cas.url,
options: cas.options,
+15 -15
View File
@@ -135,20 +135,20 @@ fn convert_task_state(
state: bollard::models::TaskState,
) -> TaskState {
match state {
bollard::secret::TaskState::NEW => TaskState::NEW,
bollard::secret::TaskState::ALLOCATED => TaskState::ALLOCATED,
bollard::secret::TaskState::PENDING => TaskState::PENDING,
bollard::secret::TaskState::ASSIGNED => TaskState::ASSIGNED,
bollard::secret::TaskState::ACCEPTED => TaskState::ACCEPTED,
bollard::secret::TaskState::PREPARING => TaskState::PREPARING,
bollard::secret::TaskState::READY => TaskState::READY,
bollard::secret::TaskState::STARTING => TaskState::STARTING,
bollard::secret::TaskState::RUNNING => TaskState::RUNNING,
bollard::secret::TaskState::COMPLETE => TaskState::COMPLETE,
bollard::secret::TaskState::SHUTDOWN => TaskState::SHUTDOWN,
bollard::secret::TaskState::FAILED => TaskState::FAILED,
bollard::secret::TaskState::REJECTED => TaskState::REJECTED,
bollard::secret::TaskState::REMOVE => TaskState::REMOVE,
bollard::secret::TaskState::ORPHANED => TaskState::ORPHANED,
bollard::config::TaskState::NEW => TaskState::NEW,
bollard::config::TaskState::ALLOCATED => TaskState::ALLOCATED,
bollard::config::TaskState::PENDING => TaskState::PENDING,
bollard::config::TaskState::ASSIGNED => TaskState::ASSIGNED,
bollard::config::TaskState::ACCEPTED => TaskState::ACCEPTED,
bollard::config::TaskState::PREPARING => TaskState::PREPARING,
bollard::config::TaskState::READY => TaskState::READY,
bollard::config::TaskState::STARTING => TaskState::STARTING,
bollard::config::TaskState::RUNNING => TaskState::RUNNING,
bollard::config::TaskState::COMPLETE => TaskState::COMPLETE,
bollard::config::TaskState::SHUTDOWN => TaskState::SHUTDOWN,
bollard::config::TaskState::FAILED => TaskState::FAILED,
bollard::config::TaskState::REJECTED => TaskState::REJECTED,
bollard::config::TaskState::REMOVE => TaskState::REMOVE,
bollard::config::TaskState::ORPHANED => TaskState::ORPHANED,
}
}
+23 -23
View File
@@ -21,13 +21,13 @@ impl DockerClient {
let scope = volume
.scope
.map(|scope| match scope {
bollard::secret::VolumeScopeEnum::EMPTY => {
bollard::config::VolumeScopeEnum::EMPTY => {
VolumeScopeEnum::Empty
}
bollard::secret::VolumeScopeEnum::LOCAL => {
bollard::config::VolumeScopeEnum::LOCAL => {
VolumeScopeEnum::Local
}
bollard::secret::VolumeScopeEnum::GLOBAL => {
bollard::config::VolumeScopeEnum::GLOBAL => {
VolumeScopeEnum::Global
}
})
@@ -69,13 +69,13 @@ impl DockerClient {
scope: volume
.scope
.map(|scope| match scope {
bollard::secret::VolumeScopeEnum::EMPTY => {
bollard::config::VolumeScopeEnum::EMPTY => {
VolumeScopeEnum::Empty
}
bollard::secret::VolumeScopeEnum::LOCAL => {
bollard::config::VolumeScopeEnum::LOCAL => {
VolumeScopeEnum::Local
}
bollard::secret::VolumeScopeEnum::GLOBAL => {
bollard::config::VolumeScopeEnum::GLOBAL => {
VolumeScopeEnum::Global
}
})
@@ -91,16 +91,16 @@ impl DockerClient {
access_mode: spec.access_mode.map(|mode| {
ClusterVolumeSpecAccessMode {
scope: mode.scope.map(|scope| match scope {
bollard::secret::ClusterVolumeSpecAccessModeScopeEnum::EMPTY => ClusterVolumeSpecAccessModeScopeEnum::Empty,
bollard::secret::ClusterVolumeSpecAccessModeScopeEnum::SINGLE => ClusterVolumeSpecAccessModeScopeEnum::Single,
bollard::secret::ClusterVolumeSpecAccessModeScopeEnum::MULTI => ClusterVolumeSpecAccessModeScopeEnum::Multi,
bollard::config::ClusterVolumeSpecAccessModeScopeEnum::EMPTY => ClusterVolumeSpecAccessModeScopeEnum::Empty,
bollard::config::ClusterVolumeSpecAccessModeScopeEnum::SINGLE => ClusterVolumeSpecAccessModeScopeEnum::Single,
bollard::config::ClusterVolumeSpecAccessModeScopeEnum::MULTI => ClusterVolumeSpecAccessModeScopeEnum::Multi,
}).unwrap_or_default(),
sharing: mode.sharing.map(|sharing| match sharing {
bollard::secret::ClusterVolumeSpecAccessModeSharingEnum::EMPTY => ClusterVolumeSpecAccessModeSharingEnum::Empty,
bollard::secret::ClusterVolumeSpecAccessModeSharingEnum::NONE => ClusterVolumeSpecAccessModeSharingEnum::None,
bollard::secret::ClusterVolumeSpecAccessModeSharingEnum::READONLY => ClusterVolumeSpecAccessModeSharingEnum::Readonly,
bollard::secret::ClusterVolumeSpecAccessModeSharingEnum::ONEWRITER => ClusterVolumeSpecAccessModeSharingEnum::Onewriter,
bollard::secret::ClusterVolumeSpecAccessModeSharingEnum::ALL => ClusterVolumeSpecAccessModeSharingEnum::All,
bollard::config::ClusterVolumeSpecAccessModeSharingEnum::EMPTY => ClusterVolumeSpecAccessModeSharingEnum::Empty,
bollard::config::ClusterVolumeSpecAccessModeSharingEnum::NONE => ClusterVolumeSpecAccessModeSharingEnum::None,
bollard::config::ClusterVolumeSpecAccessModeSharingEnum::READONLY => ClusterVolumeSpecAccessModeSharingEnum::Readonly,
bollard::config::ClusterVolumeSpecAccessModeSharingEnum::ONEWRITER => ClusterVolumeSpecAccessModeSharingEnum::Onewriter,
bollard::config::ClusterVolumeSpecAccessModeSharingEnum::ALL => ClusterVolumeSpecAccessModeSharingEnum::All,
}).unwrap_or_default(),
secrets: mode.secrets.unwrap_or_default().into_iter().map(|secret| ClusterVolumeSpecAccessModeSecrets {
key: secret.key,
@@ -116,10 +116,10 @@ impl DockerClient {
limit_bytes: range.limit_bytes,
}),
availability: mode.availability.map(|availability| match availability {
bollard::secret::ClusterVolumeSpecAccessModeAvailabilityEnum::EMPTY => ClusterVolumeSpecAccessModeAvailabilityEnum::Empty,
bollard::secret::ClusterVolumeSpecAccessModeAvailabilityEnum::ACTIVE => ClusterVolumeSpecAccessModeAvailabilityEnum::Active,
bollard::secret::ClusterVolumeSpecAccessModeAvailabilityEnum::PAUSE => ClusterVolumeSpecAccessModeAvailabilityEnum::Pause,
bollard::secret::ClusterVolumeSpecAccessModeAvailabilityEnum::DRAIN => ClusterVolumeSpecAccessModeAvailabilityEnum::Drain,
bollard::config::ClusterVolumeSpecAccessModeAvailabilityEnum::EMPTY => ClusterVolumeSpecAccessModeAvailabilityEnum::Empty,
bollard::config::ClusterVolumeSpecAccessModeAvailabilityEnum::ACTIVE => ClusterVolumeSpecAccessModeAvailabilityEnum::Active,
bollard::config::ClusterVolumeSpecAccessModeAvailabilityEnum::PAUSE => ClusterVolumeSpecAccessModeAvailabilityEnum::Pause,
bollard::config::ClusterVolumeSpecAccessModeAvailabilityEnum::DRAIN => ClusterVolumeSpecAccessModeAvailabilityEnum::Drain,
}).unwrap_or_default(),
}
}),
@@ -137,11 +137,11 @@ impl DockerClient {
.map(|status| ClusterVolumePublishStatus {
node_id: status.node_id,
state: status.state.map(|state| match state {
bollard::secret::ClusterVolumePublishStatusStateEnum::EMPTY => ClusterVolumePublishStatusStateEnum::Empty,
bollard::secret::ClusterVolumePublishStatusStateEnum::PENDING_PUBLISH => ClusterVolumePublishStatusStateEnum::PendingPublish,
bollard::secret::ClusterVolumePublishStatusStateEnum::PUBLISHED => ClusterVolumePublishStatusStateEnum::Published,
bollard::secret::ClusterVolumePublishStatusStateEnum::PENDING_NODE_UNPUBLISH => ClusterVolumePublishStatusStateEnum::PendingNodeUnpublish,
bollard::secret::ClusterVolumePublishStatusStateEnum::PENDING_CONTROLLER_UNPUBLISH => ClusterVolumePublishStatusStateEnum::PendingControllerUnpublish,
bollard::config::ClusterVolumePublishStatusStateEnum::EMPTY => ClusterVolumePublishStatusStateEnum::Empty,
bollard::config::ClusterVolumePublishStatusStateEnum::PENDING_PUBLISH => ClusterVolumePublishStatusStateEnum::PendingPublish,
bollard::config::ClusterVolumePublishStatusStateEnum::PUBLISHED => ClusterVolumePublishStatusStateEnum::Published,
bollard::config::ClusterVolumePublishStatusStateEnum::PENDING_NODE_UNPUBLISH => ClusterVolumePublishStatusStateEnum::PendingNodeUnpublish,
bollard::config::ClusterVolumePublishStatusStateEnum::PENDING_CONTROLLER_UNPUBLISH => ClusterVolumePublishStatusStateEnum::PendingControllerUnpublish,
}).unwrap_or_default(),
publish_context: status.publish_context.unwrap_or_default(),
})
+6 -9
View File
@@ -17,20 +17,17 @@
//! from the Komodo UI Settings page.
//!
//! To call the api, construct JSON bodies following
//! the schemas given in [read], [mod@write], [execute], and so on.
//! the schemas in [read], [mod@write], [execute], and so on.
//!
//! For example, this is an example body for [read::GetDeployment]:
//! ```json
//! {
//! "type": "GetDeployment",
//! "params": {
//! "deployment": "66113df3abe32960b87018dd"
//! }
//! "deployment": "my-deployment"
//! }
//! ```
//!
//! The request's parent module (eg. [read], [mod@write]) determines the http path which
//! must be used for the requests. For example, requests under [read] are made using http path `/read`.
//! The request's parent module (eg. [read], [mod@write]) and name determines the http path which
//! must be used for the requests. For example, requests under [read] are made using http path `/read/{REQUEST_NAME}`.
//!
//! ## Curl Example
//!
@@ -40,8 +37,8 @@
//! curl --header "Content-Type: application/json" \
//! --header "X-Api-Key: your_api_key" \
//! --header "X-Api-Secret: your_api_secret" \
//! --data '{ "type": "UpdateBuild", "params": { "id": "67076689ed600cfdd52ac637", "config": { "version": "1.15.9" } } }' \
//! https://komodo.example.com/write
//! --data '{ "id": "my-build", "config": { "version": "2.0.0" } }' \
//! https://komodo.example.com/write/UpdateBuild
//! ```
//!
//! ## Modules
+7 -1
View File
@@ -2,7 +2,7 @@ use mogh_resolver::Resolve;
use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::entities::ResourceTarget;
use crate::entities::{ResourceTarget, toml::ResourcesToml};
use super::KomodoReadRequest;
@@ -54,6 +54,9 @@ pub struct ExportAllResourcesToToml {
/// Default: false
#[serde(default)]
pub include_user_groups: bool,
/// Pass an existing [ResourcesToml] to preserve
/// the meta configuration.
pub existing: Option<ResourcesToml>,
}
fn default_include_resources() -> bool {
@@ -95,6 +98,9 @@ pub struct ExportResourcesToToml {
/// Whether to include variables
#[serde(default)]
pub include_variables: bool,
/// Pass an existing [ResourcesToml] to preserve
/// the meta configuration.
pub existing: Option<ResourcesToml>,
}
#[typeshare]
+35 -2
View File
@@ -1,5 +1,7 @@
use clap::ValueEnum;
use mogh_resolver::Resolve;
use serde::{Deserialize, Serialize};
use strum::Display;
use typeshare::typeshare;
use crate::entities::{api_key::ApiKey, user::User};
@@ -107,7 +109,7 @@ pub type FindUserResponse = User;
description = "**Admin only.** Gets list of Komodo users.",
request_body(content = ListUsers),
responses(
(status = 200, description = "The list of users", body = ListUsersResponse),
(status = 200, description = "The list of users", body = Vec<User>),
),
)]
pub fn list_users() {}
@@ -121,11 +123,42 @@ pub fn list_users() {}
#[empty_traits(KomodoReadRequest)]
#[response(ListUsersResponse)]
#[error(mogh_error::Error)]
pub struct ListUsers {}
pub struct ListUsers {
/// Service user query options:
/// - Include (default)
/// - Exclude
/// - Only
#[serde(default)]
pub service_users: ServiceUserQueryBehavior,
}
#[typeshare]
pub type ListUsersResponse = Vec<User>;
#[typeshare]
#[derive(
Debug,
Clone,
Copy,
Default,
Serialize,
Deserialize,
ValueEnum,
Display,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
// Only strum serializes lowercase for clap compat.
#[strum(serialize_all = "lowercase")]
pub enum ServiceUserQueryBehavior {
/// Include service users in results. Default.
#[default]
Include,
/// Exclude service users from results.
Exclude,
/// Only include service users in results.
Only,
}
//
#[cfg(feature = "utoipa")]
@@ -51,7 +51,7 @@ pub struct CreateOnboardingKey {
/// 2. Remove Server 'address' configuration, allowing Periphery -> Core connection.
/// 3. Update existing Server's public keys.
#[serde(default)]
pub fix_existing_servers: bool,
pub privileged: bool,
/// Optional. New Servers copy this Server's config.
#[serde(default)]
pub copy_server: String,
@@ -109,7 +109,7 @@ pub struct UpdateOnboardingKey {
/// 1. Enable a disabled Server
/// 2. Remove Server 'address' configuration, allowing Periphery -> Core connection.
/// 3. Update existing Server's public keys.
pub fix_existing_servers: Option<bool>,
pub privileged: Option<bool>,
/// Update the copy server
pub copy_server: Option<String>,
/// Update whether to create Builder
@@ -122,7 +122,7 @@ impl UpdateOnboardingKey {
&& self.name.is_none()
&& self.expires.is_none()
&& self.tags.is_none()
&& self.fix_existing_servers.is_none()
&& self.privileged.is_none()
&& self.copy_server.is_none()
&& self.create_builder.is_none()
}
+7 -5
View File
@@ -6,7 +6,8 @@ use crate::entities::{
NoData,
server::ServerQuery,
terminal::{
ContainerTerminalMode, TerminalRecreateMode, TerminalTarget,
ContainerTerminalMode, Terminal, TerminalRecreateMode,
TerminalTarget,
},
};
@@ -21,23 +22,24 @@ use super::KomodoWriteRequest;
description = "Create a Terminal.",
request_body(content = CreateTerminal),
responses(
(status = 200, description = "No data", body = NoData),
(status = 200, description = "The created terminal", body = Terminal),
),
)]
pub fn create_terminal() {}
/// Create a Terminal.
/// Requires minimum Read + Terminal permission on the target Resource.
/// Response: [NoData]
/// Response: [Terminal]
#[typeshare]
#[derive(Debug, Clone, Serialize, Deserialize, Resolve)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[empty_traits(KomodoWriteRequest)]
#[response(NoData)]
#[response(Terminal)]
#[error(mogh_error::Error)]
pub struct CreateTerminal {
/// A name for the Terminal session.
pub name: String,
/// If not specified, a default will be given.
pub name: Option<String>,
/// The target to create terminal for
pub target: TerminalTarget,
/// The shell command (eg `bash`) to init the shell.
@@ -0,0 +1,59 @@
#[derive(Debug, Clone, clap::Subcommand)]
pub enum CreateCommand {
/// Create a new api key. (alias: `ak`)
#[clap(alias = "ak")]
ApiKey(CreateApiKey),
/// Create a new onboarding key. (alias: `ok`)
#[clap(alias = "ok")]
OnboardingKey(CreateOnboardingKey),
}
/// Create a new API key.
#[derive(Debug, Clone, clap::Parser)]
pub struct CreateApiKey {
/// Pass optional name for the api key
pub name: Option<String>,
/// The user username to create the API key for.
/// If `--use-api`, this is optional, and will create an api key for a service user.
/// If NOT `--use-api` (default), this field is REQUIRED.
#[arg(long = "for", short = 'f')]
pub for_user: Option<String>,
/// Pass api key expiry in number of days. Default: Unlimited.
#[arg(long, short = 'e')]
pub expires: Option<i64>,
/// Use the Komodo API rather than direct database connection.
/// This requires existing km credentials.
#[arg(long, short = 'a', default_value_t = false)]
pub use_api: bool,
}
/// Create a new onboarding key.
#[derive(Debug, Clone, clap::Parser)]
pub struct CreateOnboardingKey {
/// Pass optional name for the onboarding key
pub name: Option<String>,
/// Pass onboarding key expiry in number of days. Default: Unlimited.
#[arg(long, short = 'e')]
pub expires: Option<i64>,
/// Pass an existing private key, otherwise one will be generated. (alias: `pk`)
#[arg(long, alias = "pk", short = 'k')]
pub private_key: Option<String>,
/// Add creation tags to onboarding key.
/// Can be specified multiple times. (alias `t`)
#[arg(name = "tag", long, short = 't')]
pub tags: Vec<String>,
/// Make the onboarding key privileged.
#[arg(long, short = 'p', default_value_t = false)]
pub privileged: bool,
/// Optional. Onboarded Servers copy this Server's config. (aliases: `copy`, `server`)
#[arg(long, alias = "copy", alias = "server", short = 's')]
pub copy_server: Option<String>,
/// Optional. Whether to also create a Builder for the Server. (alias: `builder`)
#[arg(
long,
alias = "builder",
short = 'b',
default_value_t = false
)]
pub create_builder: bool,
}
@@ -5,6 +5,7 @@ use std::path::PathBuf;
use crate::api::execute::Execution;
pub mod container;
pub mod create;
pub mod database;
pub mod list;
pub mod terminal;
@@ -52,6 +53,10 @@ pub enum Command {
unsanitized: bool,
},
/// Print information about the connected Komodo Core. (alias: `core`)
#[clap(alias = "core")]
CoreInfo,
/// List Komodo resources (aliases: `ls`, `resources`)
#[clap(alias = "ls", alias = "resources")]
List(list::List),
@@ -66,6 +71,13 @@ pub enum Command {
)]
Execute(Execute),
/// Create resources. (aliases: `new`, `cr`)
#[clap(alias = "new", alias = "cr")]
Create {
#[command(subcommand)]
command: create::CreateCommand,
},
/// Update resource configuration. (alias: `set`)
#[clap(alias = "set")]
Update {

Some files were not shown because too many files have changed in this diff Show More