Compare commits

..
614 Commits
Author SHA1 Message Date
mbecker20 b5b680dd1d Deploy / DeployStack updates invalidate corresponding list query 2026-03-05 10:40:19 -08:00
mbecker20 bf5ac8b6ac deploy 2.0.0-dev-123 2026-03-05 10:32:39 -08:00
mbecker20 dcccc878c8 mogh auth 1.2.11 2026-03-05 10:27:37 -08:00
mbecker20 1c87fba8f5 mogh auth server 1.2.10 2026-03-05 10:04:25 -08:00
mbecker20 2fc35b3c2d debug level core <> periphery auth identifiers logs 2026-03-05 00:10:30 -08:00
mbecker20 2012fd1dd9 deploy 2.0.0-dev-122 2026-03-04 19:37:13 -08:00
mbecker20 550c0339d6 read request are trace 2026-03-04 19:36:34 -08:00
mbecker20 50cf2f2d50 fmt 2026-03-04 16:31:13 -08:00
mbecker20 b223fefec6 notification green contents written success 2026-03-04 16:19:44 -08:00
mbecker20 7fe56f72ae setters use maps instead of mutations 2026-03-04 16:14:57 -08:00
mbecker20 0a9bc397ca config sidebar save 2026-03-04 15:58:09 -08:00
mbecker20 a03fceba7f thinner topbar 2026-03-04 10:46:45 -08:00
mbecker20 1bf1574c2a rename for clarity 2026-03-03 12:40:25 -08:00
mbecker20 83d90e0a16 improve disk usage hover card styling 2026-03-02 20:39:50 -08:00
mbecker20 304ffbf01d Add hoverable disk info 2026-03-02 20:32:34 -08:00
mbecker20 07787d6fa1 "never" -> "Never" 2026-03-02 19:59:30 -08:00
mbecker20 5d04142a99 fix sidebar margin right 2026-02-27 14:21:15 -08:00
mbecker20 aecba3be9f refine lg screen size view 2026-02-27 14:19:28 -08:00
mbecker20 4c4e5b62e0 taller data table and blue omnisearch 2026-02-27 13:10:46 -08:00
mbecker20 62f0ca9093 tweaks for lg size 2026-02-27 03:39:01 -08:00
mbecker20 3d43e2419f Update / Alert table filter selector formatted 2026-02-27 02:06:35 -08:00
mbecker20 d4081c2d6b single delete terminal 2026-02-26 18:52:39 -08:00
mbecker20 d397cb4ea4 fix terminal height - same as logs 2026-02-26 18:35:03 -08:00
mbecker20 0c96e24cd4 fix some wrapping stuff in tables and tag text disappear 2026-02-26 18:15:39 -08:00
mbecker20 1c90e768ef fix login github / google icon color 2026-02-26 16:55:01 -08:00
mbecker20 be73f20fd5 improve login styling 2026-02-26 16:47:15 -08:00
mbecker20 330178dbb8 standard api key modal size 2026-02-26 16:30:03 -08:00
mbecker20 c8c01307a0 improve profile delete styling 2026-02-26 16:27:42 -08:00
mbecker20 2e80adff2d deploy 2.0.0-dev-121 2026-02-26 16:13:04 -08:00
mbecker20 ef5a0982cb post link redirect should be to profile 2026-02-26 15:56:37 -08:00
mbecker20 9ffa40022d topbar user dropdown shows user avatar if available 2026-02-26 15:49:03 -08:00
mbecker20 15eaeab68d deploy 2.0.0-dev-120 2026-02-26 15:06:15 -08:00
mbecker20 89ea5ad5a4 stack and deployment state color include update available. Ensure server version mismatch color applied everywhere 2026-02-26 15:02:37 -08:00
mbecker20 c05dde3678 add close button to update / alert details drawer 2026-02-26 14:43:24 -08:00
mbecker20 a17a1005c7 smaller more consistent gaps 2026-02-26 14:38:36 -08:00
mbecker20 d13314eb98 stack stopped and deployment exited warning instead of critical 2026-02-26 14:25:31 -08:00
mbecker20 f41a61116a fix batch executions width 2026-02-26 14:24:58 -08:00
mbecker20 13fbcae105 edit swarm join command 2026-02-26 14:09:01 -08:00
mbecker20 71c437962f ensure section headers consistent spacing 2026-02-26 14:06:57 -08:00
mbecker20 e4147ccdaf rename ConfigSwitch onChange -> onCheckedChange 2026-02-26 13:41:51 -08:00
mbecker20 5089375211 improve tab styling 2026-02-26 13:38:07 -08:00
mbecker20 e489812af4 Fix config input issue 2026-02-26 13:37:32 -08:00
mbecker20 7373ff8d0e execution buttons disabled when loading 2026-02-26 12:53:58 -08:00
mbecker20 4e1cd32f3f Select Template 2026-02-25 19:31:28 -08:00
mbecker20 57211746f1 hide actions when none 2026-02-25 19:21:48 -08:00
mbecker20 5e153fb02b dashboard active styling 2026-02-25 19:21:22 -08:00
mbecker20 b28a413005 procedure / action webhook branch mobile style 2026-02-25 17:46:22 -08:00
mbecker20 691671abbd Load Average is first historical stat 2026-02-25 17:43:54 -08:00
mbecker20 504e81c2f7 improve login no auth configured and passkey pending 2026-02-25 17:36:02 -08:00
mbecker20 0a479a0f4a bump chef rust version 2026-02-25 16:08:55 -08:00
mbecker20 6a05779ceb deploy 2.0.0-dev-118 2026-02-25 16:07:05 -08:00
mbecker20 acd27ba058 bump rust version to 1.93.1 and dep versions 2026-02-25 16:06:37 -08:00
Maxwell BeckerandGitHub 96c4ae9fc5 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
2026-02-25 15:28:23 -08:00
mbecker20 5c99958cba only send auto updated alert after verifying the deploy was successful 2026-02-15 18:38:01 -08:00
mbecker20 7288f067c5 deploy 2.0.0-dev-116 2026-02-11 10:20:39 -08:00
mbecker20 5d0f7de9fb Stack check for update prefers check against deployed service image 2026-02-11 10:20:09 -08:00
mbecker20 4129abcfd0 add new config value to example config 2026-01-27 23:26:44 -08:00
mbecker20 4275e903eb deploy 2.0.0-dev-115 2026-01-27 23:19:49 -08:00
mbecker20 c57c321cbb configure session allow cross site 2026-01-27 23:19:20 -08:00
mbecker20 9a7d49b35e bump mogh server and auth 2026-01-27 22:51:05 -08:00
mbecker20 d6aaef24cd bump rust to 1.93.0 2026-01-27 13:42:20 -08:00
mbecker20 3dce84c1f5 deploy 2.0.0-dev-114 2026-01-27 12:58:57 -08:00
mbecker20 8b16f97caf check update available against all digests for image 2026-01-27 12:58:32 -08:00
mbecker20 c98a809db4 serve static ui index.html with ETag / no-cache 2026-01-25 12:36:40 -08:00
mbecker20 c066b4fe16 mogh_server = "1.2.0" 2026-01-25 11:26:17 -08:00
mbecker20 b54fa235bc dev-113 2026-01-24 12:48:38 -08:00
mbecker20 05fd1aba2c batch check for updates, add check to table multi select actions 2026-01-24 12:48:13 -08:00
mbecker20 1a5290e124 cleanup 2026-01-24 11:33:49 -08:00
mbecker20 538e11ef3b dev 112 2026-01-24 11:33:22 -08:00
mbecker20 9208e9bf86 skip auto update for images with pinned digest 2026-01-24 11:30:41 -08:00
mbecker20 31640e3df8 fix require to import 2026-01-24 01:06:15 -08:00
mbecker20 42751d1b90 fix tailwind config module 2026-01-24 01:04:31 -08:00
mbecker20 673ab5c17d bump node version in all the dockerfiles 2026-01-24 01:01:05 -08:00
mbecker20 ad00f38758 bump frontend node version 2026-01-24 00:59:42 -08:00
mbecker20 b2459b5a64 align dashboard icon with sidebar 2026-01-24 00:58:23 -08:00
mbecker20 5923dd0e22 use mogh auth for passkey conversion 2026-01-24 00:45:32 -08:00
mbecker20 51294edd73 bump ts types and fix SwarmConfig type name conflict 2026-01-23 20:26:43 -08:00
mbecker20 baf77bf701 add api docs link 2026-01-23 14:59:22 -08:00
mbecker20 ddd99dc85d deploy 2.0.0-dev-111 2026-01-23 14:39:36 -08:00
mbecker20 a4c902282d improve swarm service / stack state inference 2026-01-23 14:39:00 -08:00
mbecker20 d7a2d4aadc clean up dangling action api keys on startup 2026-01-23 11:37:50 -08:00
mbecker20 c930468811 fix Action import from terminal 2026-01-23 03:11:47 -08:00
mbecker20 27efc81451 stack level terminal page 2026-01-23 03:07:57 -08:00
mbecker20 e44bd324f7 finish version upgrades page, and use prism theme oneLight and oneDark 2026-01-23 02:10:16 -08:00
mbecker20 b64c7e7289 deploy 2.0.0-dev-110 2026-01-23 01:10:32 -08:00
mbecker20 5c1a17fc91 improve config styling a bit more 2026-01-23 01:10:06 -08:00
mbecker20 50c3d77aed improve config quick links styling 2026-01-23 00:50:51 -08:00
mbecker20 bba1e3ae0c typegen 2026-01-23 00:24:27 -08:00
mbecker20 fc26fede66 add back legacy Action "exec" method calling convention 2026-01-23 00:23:54 -08:00
mbecker20 9cee723a1a deploy 2.0.0-dev-109 2026-01-22 19:12:55 -08:00
mbecker20 b922e86d29 deploy 2.0.0-dev-108 2026-01-22 18:38:12 -08:00
mbecker20 85dd3c0fe9 cache latest image digests and use this for image update alerting / auto update 2026-01-22 18:37:43 -08:00
mbecker20 4e3ecf7e6c clean up 2026-01-21 03:38:48 -08:00
mbecker20 18ffe635c8 remove user api, mogh auth handles api keys 2026-01-21 02:24:21 -08:00
mbecker20 8758c9ff8b gen types 2026-01-20 03:08:43 -08:00
mbecker20 5da48ece82 fmt and bump mogh auth 2026-01-20 02:58:45 -08:00
mbecker20 9a48edc43f add the write openapi definitions 2026-01-19 23:49:12 -08:00
mbecker20 93430f6dc3 more write openapi 2026-01-19 23:34:18 -08:00
mbecker20 d893ae9241 most of write openapi 2026-01-19 23:02:48 -08:00
mbecker20 24ed3cfcb1 server / stack exec openapi 2026-01-19 22:18:41 -08:00
mbecker20 36ee7ed72e most of execute openapi 2026-01-19 22:10:16 -08:00
mbecker20 5895fb843e modularize openapi structs 2026-01-19 20:50:08 -08:00
mbecker20 98f53020fb add most basic read apis 2026-01-19 19:33:18 -08:00
mbecker20 1d10873e77 improve toml comment 2026-01-19 18:03:36 -08:00
mbecker20 f5ee42029f review / fix some openapi definitions 2026-01-19 17:57:59 -08:00
mbecker20 525402f6f2 add openapi definitions to most read apis 2026-01-19 17:42:04 -08:00
mbecker20 9f877cc188 move openapi definition into client lib under feature gate 2026-01-19 15:41:38 -08:00
mbecker20 69d6b8e6ec remove the patch 2026-01-19 01:24:50 -08:00
mbecker20 526bcc1907 deploy 2.0.0-dev-107 2026-01-19 01:22:59 -08:00
mbecker20 f7badf5579 define set logging module targets so log level becomes useful 2026-01-19 01:18:50 -08:00
mbecker20 86fd7a155d try deno npm: style dep 2026-01-19 00:25:11 -08:00
mbecker20 628afc3baa deploy 2.0.0-dev-106 2026-01-18 23:37:19 -08:00
mbecker20 04f944fcc2 use full mogh dep names 2026-01-18 23:36:52 -08:00
mbecker20 f39447b513 move to mogh_resolver 2026-01-18 22:56:13 -08:00
mbecker20 612acd02ad remove derive_variants, strum's "EnumDiscriminants" covers it 2026-01-18 22:30:54 -08:00
mbecker20 90557ae514 fix cors options 2026-01-18 19:35:21 -08:00
mbecker20 0c292f7157 deploy 2.0.0-dev-105 2026-01-18 18:16:32 -08:00
mbecker20 673ee05fe9 tmp back to 104 2026-01-18 18:16:30 -08:00
mbecker20 94b5bd6660 use public ts mogh auth client 2026-01-18 16:52:49 -08:00
mbecker20 be40110004 use mogh_auth embedded api 2026-01-18 16:31:45 -08:00
mbecker20 2d4a34b820 move to mogh deps 2026-01-17 23:22:58 -08:00
mbecker20 2feb08725b fix_ws_address adds 'ws://' to direct IPs instead of 'wss://' which won't work 2026-01-06 10:14:10 -08:00
mbecker20 161393805f refactor openapi -> utoipa feature 2026-01-05 12:45:52 -08:00
mbecker20 f4b692080d remove user_id from jwt response -- its encoded transparently in jwt 2026-01-05 12:38:17 -08:00
mbecker20 e1c6c866a2 docs.html 2025-12-30 14:33:34 -08:00
mbecker20 7106328390 add authentication to openapi docs 2025-12-30 14:32:29 -08:00
mbecker20 338acba5c6 start utoipa openapi support 2025-12-30 13:02:27 -08:00
mbecker20 dcf6f2431e tweak 2025-12-29 22:31:19 -08:00
mbecker20 58b520e651 improve OIDC client init to only as needed 2025-12-29 11:22:49 -08:00
mbecker20 8be0846733 bump axum-extra 2025-12-28 10:15:00 -08:00
mbecker20 5b651f2527 tweak 2025-12-27 15:11:13 -08:00
mbecker20 026ba4fca8 use User constructor 2025-12-27 02:14:16 -08:00
mbecker20 4bca07d4ba update deps 2025-12-27 01:47:54 -08:00
mbecker20 9091f14711 update password refetch user 2025-12-26 02:07:44 -08:00
mbecker20 8b78bb838e fix alert error messages - reference correct alerter type 2025-12-26 01:57:23 -08:00
mbecker20 d384f7ca78 update to v2 docs 2025-12-24 00:46:07 -08:00
mbecker20 48475b55d5 Periphery GetLatestImageDigest + RollbackSwarmService 2025-12-21 00:58:57 -08:00
mbecker20 64d7959c75 bump deps 2025-12-21 00:57:46 -08:00
mbecker20 d1856c2325 deploy 2.0.0-dev-104 2025-12-20 12:30:03 -08:00
mbecker20 61b7fcdb0a onboarding key fix_existing_servers / priviledged 2025-12-20 12:29:24 -08:00
mbecker20 2693f13829 deploy 2.0.0-dev-103 2025-12-19 12:22:51 -08:00
mbecker20 7fea06861b improve swarm node page 2025-12-19 12:22:20 -08:00
mbecker20 abd155193a join swarm command 2025-12-19 12:10:25 -08:00
mbecker20 7a4de0343d config / secret has service and task tables 2025-12-18 15:30:37 -08:00
mbecker20 c638e3876e deploy 2.0.0-dev-102 2025-12-18 14:52:04 -08:00
mbecker20 fc4ea40b9c task links to configs / secrets 2025-12-18 13:43:16 -08:00
mbecker20 62b84328d8 link attached configs / secrets in status 2025-12-18 13:29:38 -08:00
mbecker20 a5ee0de394 tweaks 2025-12-18 02:32:08 -08:00
mbecker20 bf0ab26d22 improve swarm deployments 2025-12-18 01:36:31 -08:00
mbecker20 0dd2ade574 fix config / secret rotation 2025-12-17 12:59:08 -08:00
mbecker20 f0172c2721 move inspect to swarm tabs top level 2025-12-15 22:55:37 -08:00
mbecker20 363d330868 similar but inherently limited swarm secret management 2025-12-15 22:49:45 -08:00
mbecker20 2843711796 swarm config create / edit / delete 2025-12-15 17:04:03 -08:00
mbecker20 4f044ccde8 Service aware config rotation 2025-12-14 14:42:53 -08:00
mbecker20 9be21b54bd fix deployment / stack toml when swarm attached 2025-12-14 00:06:12 -08:00
mbecker20 057ecbcfef add load passkey frontend indicator screen 2025-12-13 23:43:13 -08:00
mbecker20 e91d63f262 deploy 2.0.0-dev-101 2025-12-13 18:37:39 -08:00
mbecker20 3b799edb30 improve the swarm tables 2025-12-13 18:37:14 -08:00
mbecker20 41c7faf48d add resources tab to swarms 2025-12-13 11:21:24 -08:00
mbecker20 e1d745aee0 status colors for swarm resources 2025-12-13 11:12:26 -08:00
mbecker20 01df3add41 Fix task state check 2025-12-13 01:01:22 -08:00
mbecker20 577973841b better api / onboarding key shape 2025-12-12 23:59:42 -08:00
mbecker20 3e5311f413 user profile mobile 2025-12-12 18:30:00 -08:00
mbecker20 46e99783f2 deploy 2.0.0-dev-100 2025-12-12 18:00:28 -08:00
mbecker20 a6590804a7 skip 2fa for third party logins 2025-12-12 18:00:03 -08:00
mbecker20 bd752b7c72 deploy 2.0.0-dev-99 2025-12-12 17:08:45 -08:00
mbecker20 de83b3a5a0 user link multiple primary login methods 2025-12-12 17:08:03 -08:00
mbecker20 c91963fdbb fix table_borders in cli config 2025-12-11 01:03:43 -08:00
mbecker20andMaxwell Becker 973aae82fd improve 2fa ux 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker c3626e0949 cli support clearing users 2fa methods 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 5ba96a58e4 binaries use bookworm 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker c6a1cf2867 deploy 2.0.0-dev-98 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker bd39aec1fd support passkey 2fa 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 079895a64d fix imports in permissions module 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 5af1c646a5 deploy 2.0.0-dev-97 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 747e03b5c4 Fix incorrect permissions query due to resource RBAC update query filter. Align logic with Alert resource RBAC filter. Re #1011 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 78c6761eca add swarm specific permission config 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker a949891d26 apply login credential lock (for demo users) to 2FA 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 9d256e420a improve totp enrollment dialog closing, fix redirect away from /login when using two factor 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker b460504b5a deploy 2.0.0-dev-96 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker e60316f2c1 TOTP 2FA with third party logins 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker c45e3eab16 deploy 2.0.0-dev-95 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker ec12f63272 double recovery code length 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker f2f77b4eb6 totp unenroll 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 677a65f8b0 local login TOTP 2fa support 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker a5a1090177 deploy 2.0.0-dev-94 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker ccb18fc88a fix server auto rotate keys default for sync 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 0ca583fe5e deploy Deployments to swarms 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 4013cd3f1e dev-93 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 5854a7de99 Deployment as swarm service 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 8c52232852 swarm stack deploy and destroy 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker fb9e5b1860 ts types 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker a1c00a8d32 implement the swarm resource associations for stack / deployment targeting swarm 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 775f5bf703 more stack / deployment deploy on swarm 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker effe737ffe periphery swarm stack deploy 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 436959cbcd docker service create 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 9957287443 remove buttons for swarm resources 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker c77de8683c swarm stack logs and Remove 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 087bcb7044 improve swarm stack page 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 0dfcaaf06a add swarm remove executions to procedure UI excluded types 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 6624a821a5 deploy 2.0.0-dev-92 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker c32af84e02 remove swarm entities apis 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 9d9add7b34 Uppercase server docker ops logs 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker db099dbe1e improve config with tall linkto sidebars 2025-12-10 21:39:56 -08:00
mbecker20andMaxwell Becker 413a8abc84 default rate limit attempts to 5 per 15 sec 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 36243e83c1 KL-4 must fallback to axum extracted IP for cases not using reverse proxy 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 076113a1de KL-4: Align log consistency 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker c998edaa73 KL-1: core_allowed_origins example config should be empty 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 4de32b08e5 KL-8 modify action state internal behavior comments 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 262999c58f KL-7 Improve typescript safety: disable allow any 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker be57f52e6e KL-6 Improve error handling in startup paths 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 3591789316 KL-6 Improve alert cache error handling 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 83f2bd65fe KL-6 Remove monitoring_interval panic 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 5e5cdb81f8 KL-5 ext: Tighten the skew tolerance re https://curity.io/resources/learn/jwt-best-practices/?utm_source=chatgpt.com#9-dealing-with-time-based-claims 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 721038a1df KL-5 JWT clock skew tolerance 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 7de98ad519 cargo clippy and bump to rust 1.91.1 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 8c62f2b5c5 KL-4 ext 2: Improve rate limiting / attempt state conveyance with response 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 85787781ee KL-4 ext: Remove brute-force compromising credential failure reasons to improve auth rate limiter effectiveness 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 25e2d4e926 KL-4 Authentication rate limiting 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker b9b8d45cbc KL-2/3 Input validation for local auth, service users, api keys, and variables 2025-12-10 21:34:30 -08:00
mbecker20andMaxwell Becker 2f2e863dbf KL-1 Configurable CORS support 2025-12-10 21:34:30 -08:00
mbecker20 a3a01f1625 add schemas for swarm commands 2025-11-27 23:47:22 -08:00
mbecker20 aec8fa2bf1 task view page with logs 2025-11-23 23:45:28 -08:00
mbecker20 7ff2dba82f swarm service page with logs 2025-11-23 12:48:23 -08:00
mbecker20 9c86b2d239 swarm service logs api 2025-11-23 00:43:59 -08:00
mbecker20 b1fec7c663 docker swarm stack read apis 2025-11-22 16:05:51 -08:00
mbecker20 8341c6b802 sward resources use list items 2025-11-22 02:41:49 -08:00
mbecker20 73285c4374 move swarm to list item + inspect on pages 2025-11-21 14:34:20 -08:00
mbecker20 32d48cdb02 swarm configs view 2025-11-21 13:21:14 -08:00
mbecker20 8e081fd09c swarm config apis 2025-11-21 12:55:37 -08:00
mbecker20 04531f1dea Explore swarm info 2025-11-20 13:00:29 -08:00
mbecker20 80f439d472 basic swarm 2025-11-19 18:02:50 -08:00
mbecker20 d5e03d6d16 prog on swarm 2025-11-19 01:48:43 -08:00
mbecker20 a9f55bb8e6 fix Terminals permissions when no perm on Server 2025-11-17 15:44:14 -08:00
mbecker20 9e765f93f5 bump deps 2025-11-17 15:43:56 -08:00
mbecker20 b3aa8e906f add context to onboarding login error and error messages sent over the communication websocket in general 2025-11-17 13:23:44 -08:00
mbecker20 03fe442aa0 in prog 2025-11-17 12:59:08 -08:00
ChanningHeandGitHub d268009a6a validate compose_cmd_wrapper for required placeholder and add interpolation support (#977) 2025-11-12 10:09:15 -08:00
mbecker20 f0697e812a shift + N open new variable dialog 2025-11-11 14:22:56 -08:00
mbecker20 78766463d6 create variable Enter submit 2025-11-11 14:18:28 -08:00
mbecker20 0fa1edba2c deploy 2.0.0-dev-90 2025-11-11 14:13:55 -08:00
mbecker20 bbd968cac3 bump toml pretty with fix syncing procedure executions with multiline batch patterns 2025-11-11 14:13:25 -08:00
mbecker20 5f24fc1be3 deploy 2.0.0-dev-89 2025-11-11 00:44:49 -08:00
mbecker20 7ecd2b0b0b improve cmd wrapper with comment removal support 2025-11-11 00:43:54 -08:00
mbecker20 7bf44d2e04 fix some broken tabs 2025-11-11 00:35:24 -08:00
mbecker20 24e0672384 dashboard resets page title 2025-11-11 00:18:16 -08:00
mbecker20 04f081631f deploy 2.0.0-dev-88 2025-11-11 00:16:07 -08:00
mbecker20 b1af956b63 fix dashboard pie chart code splitting issue 2025-11-11 00:05:32 -08:00
mbecker20 370712b29f gen served client types 2025-11-11 00:05:02 -08:00
mbecker20 2b6c552964 canius lite update 2025-11-11 00:04:52 -08:00
mbecker20 434a1d8ea9 clippy lint 2025-11-11 00:04:39 -08:00
ChanningHeandGitHub 0b7f28360f Add optional command wrapper for Docker Compose in StackConfig (#973) 2025-11-10 23:59:09 -08:00
ChanningHeandGitHub 3c8ef0ab29 Add track option for Additional Env Files (#955) 2025-11-10 23:47:07 -08:00
mbecker20 930b2423c3 deploy 2.0.0-dev-87 2025-11-07 10:33:23 -08:00
mbecker20 546747b5f2 add timeout to dns ip resolve, only use ipv4 2025-11-07 10:32:55 -08:00
mbecker20 c6df866755 better aws builder config organization 2025-11-07 10:04:45 -08:00
mbecker20 ea5e684915 better useUserTargetPermissions 2025-11-06 22:18:31 -08:00
mbecker20 64db8933de RefreshBuildCache after build 2025-11-04 00:27:34 -08:00
mbecker20 7a5580de57 builder uppercase login 2025-11-04 00:06:46 -08:00
mbecker20 b1656bb174 log about enabling user linger 2025-11-03 10:29:50 -08:00
Badal SinghandGitHub 559ce103da Update setup-periphery.py (#958) 2025-11-03 09:57:49 -08:00
mbecker20 75e278a57b builder fix partial_default 2025-10-30 00:41:27 -07:00
mbecker20 430f3ddc34 fix omni search container double select on same name 2025-10-29 00:02:32 -07:00
mbecker20 6c30c202e9 add Terminals to omni search 2025-10-28 23:59:41 -07:00
mbecker20 c5401de1c5 tweak user level tab view 2025-10-28 11:42:29 -07:00
mbecker20 7a3d9e0ef6 tweak description 2025-10-28 00:32:39 -07:00
mbecker20 595e3ece42 deploy 2.0.0-dev-86 2025-10-27 21:05:13 -07:00
mbecker20 a3bc895755 fix terminal disconnect 2025-10-27 21:04:46 -07:00
mbecker20 3e3def03ec terminal init properly lexes init command 2025-10-27 21:01:15 -07:00
mbecker20 bc672d9649 deploy 2.0.0-dev-85 2025-10-27 20:01:18 -07:00
mbecker20 ea6dee4d51 clippy lint 2025-10-27 19:13:43 -07:00
mbecker20 b985f18c74 deploy 2.0.0-dev-84 2025-10-27 19:12:54 -07:00
mbecker20 45909b2f04 pid1 reaper doesn't work, init: true should be required in compose 2025-10-27 19:06:50 -07:00
mbecker20 2b5a54ce89 deploy 2.0.0-dev-83 2025-10-27 18:31:56 -07:00
mbecker20 a18f33b95e formalize the terminal message variants 2025-10-27 18:31:30 -07:00
mbecker20 f35b00ea95 bump clap dependency 2025-10-27 16:18:30 -07:00
mbecker20 70fab08520 clean up terminal modules 2025-10-27 16:17:20 -07:00
mbecker20 0331780a5f rename variables shell -> command 2025-10-27 11:08:57 -07:00
mbecker20 06cdfd2bbc Terminal -> Terminals tabs 2025-10-27 02:53:06 -07:00
mbecker20 1555202569 Create Terminal don't auto set request after changed 2025-10-27 02:42:06 -07:00
mbecker20 5139622aad deploy 2.0.0-dev-82 2025-10-27 02:28:48 -07:00
mbecker20 61ce2ee3db improve new terminal 2025-10-27 02:04:15 -07:00
mbecker20 3171c14f2b comment on spawn process reaper 2025-10-27 01:41:06 -07:00
mbecker20 521db748d8 deploy 2.0.0-dev-81 2025-10-27 01:27:42 -07:00
mbecker20 35bf224080 deploy 2.0.0-dev-80 2025-10-27 01:21:44 -07:00
mbecker20 e0b31cfe51 CreateTerminal only shows resources which are actually available to connect to 2025-10-27 00:44:56 -07:00
mbecker20 0a890078b0 deploy 2.0.0-dev-79 2025-10-27 00:38:08 -07:00
mbecker20 df97ced7a4 deploy 2.0.0-dev-78 2025-10-27 00:03:26 -07:00
mbecker20 d4e5e2e6d8 add execute_<>_terminal convenience methods 2025-10-26 23:35:17 -07:00
mbecker20 19aa60dcb5 deploy 2.0.0-dev-77 2025-10-26 23:21:15 -07:00
mbecker20 fc19c53e6f deploy 2.0.0-dev-76 2025-10-26 23:00:59 -07:00
mbecker20 4f0af960db Big Terminal refactor + most commands run directly / bypass 'sh -c "..."' 2025-10-26 23:00:35 -07:00
mbecker20 e2ec5258fb add "New" kb shortcut 2025-10-23 23:55:24 -07:00
mbecker20 49b6545a02 reorder cli command list 2025-10-23 23:53:10 -07:00
mbecker20 0aabaa9e62 deploy 2.0.0-dev-75 2025-10-23 12:23:10 -07:00
mbecker20 dc65986eab binaries still built with bullseye for compat, but final images use trixie 2025-10-23 12:22:50 -07:00
mbecker20 1d8f28437d km attach <CONTAINER> 2025-10-23 12:22:02 -07:00
mbecker20 c1502e89c2 deploy 2.0.0-dev-74 2025-10-23 11:51:40 -07:00
mbecker20 0bd15fc442 ResourceQuery.names supports names or ids 2025-10-23 11:23:37 -07:00
mbecker20 5a3621b02e km exec 2025-10-23 01:55:50 -07:00
mbecker20 38192e2dac deploy 2.0.0-dev-73 2025-10-23 00:56:15 -07:00
mbecker20 5d271d5547 use Ping timeout to handle reconnect if for some reason network cuts but ws doesn't receive Close 2025-10-23 00:55:51 -07:00
mbecker20 11fb67a35b ssh use cancel token so stdout.write_all isn't cancelled mid-write, which leads to undefined behavior 2025-10-23 00:14:17 -07:00
mbecker20 a80499dcc4 improve stack config files responsive 2025-10-22 19:02:30 -07:00
mbecker20 8c76b8487f alert responsive, better Server terminal disabled 2025-10-22 13:48:08 -07:00
mbecker20 2b32d9042a deploy 2.0.0-dev-72 2025-10-22 01:00:19 -07:00
mbecker20 dc48f1f2ca deploy 2.0.0-dev-71 2025-10-22 00:50:02 -07:00
mbecker20 8e7b7bdcf1 deploy 2.0.0-dev-70 2025-10-22 00:44:54 -07:00
mbecker20 f11d64f72e add 'init' param to make 'execute_terminal' in single call possible 2025-10-22 00:44:33 -07:00
mbecker20 2ffae85180 dashboard table section headers link to resources page 2025-10-22 00:03:12 -07:00
mbecker20 bd79d0f1e0 km ssh <SERVER> [COMMAND] -n [NAME] 2025-10-21 23:55:36 -07:00
mbecker20 e890b1f675 deploy 2.0.0-dev-69 2025-10-21 23:32:18 -07:00
mbecker20 3b7de25c30 Shift + X - Terminals, Shift + N - New (Resource, Terminal) 2025-10-21 16:11:27 -07:00
mbecker20 793bb99f31 nav to terminal on create 2025-10-21 16:00:50 -07:00
mbecker20 d465c9f273 deploy 2.0.0-dev-68 2025-10-21 15:51:38 -07:00
mbecker20 ce641a8974 terminal page 2025-10-21 15:51:18 -07:00
mbecker20 1b89ceb122 deploy 2.0.0-dev-67 2025-10-21 02:50:21 -07:00
mbecker20 2dbc011d26 remove unneeded log on client terminal disconnect 2025-10-21 02:33:19 -07:00
mbecker20 246da88ae1 deploy 2.0.0-dev-66 2025-10-21 02:29:12 -07:00
mbecker20 a8c16f64b1 km ssh 2025-10-21 02:28:42 -07:00
mbecker20 a5b711a348 stack tabs localstorage increment 2025-10-20 20:35:08 -07:00
mbecker20 9666e9ad83 Fix monitoring table with proper server version component 2025-10-20 03:01:07 -07:00
mbecker20 7479640c73 add hover information for mysterious server header icons 2025-10-20 02:53:18 -07:00
mbecker20 4823825035 give websocket indicator info on hover 2025-10-20 02:35:12 -07:00
mbecker20 23897a7acf clippy 2025-10-20 02:16:52 -07:00
mbecker20 20d5588b5c deploy 2.0.0-dev-65 2025-10-20 02:15:15 -07:00
mbecker20 f7e15ccde5 progress on terminals page 2025-10-20 02:14:51 -07:00
mbecker20 cf7623b1fc combine all resources / table view into dashboard 2025-10-20 01:40:27 -07:00
mbecker20 d3c464c05d start Terminals management page 2025-10-20 00:42:45 -07:00
mbecker20 5c9d416aa4 prog on docs update 2025-10-19 23:33:41 -07:00
mbecker20 aabcd88312 update connect-servers docs 2025-10-19 23:07:50 -07:00
mbecker20 9d2624c6bc clarify root directory in periphery config file 2025-10-19 23:07:19 -07:00
mbecker20 ee11fb0b6c clean up setup script 2025-10-19 23:07:02 -07:00
mbecker20 45adfbddd0 mounting custom CA 2025-10-19 23:06:48 -07:00
mbecker20 d26d035dc6 clean up docs intro 2025-10-19 22:03:17 -07:00
mbecker20 e673ba0adf deploy 2.0.0-dev-64 2025-10-19 21:48:15 -07:00
mbecker20 f876facfa7 improve git status message / failure propogation 2025-10-19 21:47:29 -07:00
mbecker20 3a47d57478 container class px-[1.2rem] 2025-10-19 20:31:40 -07:00
mbecker20 a707028277 responsive tweaks 2025-10-19 20:07:30 -07:00
mbecker20 0c6276c677 fix Resources / Containers mobile 2025-10-19 19:51:28 -07:00
mbecker20 fc9c6706f1 keep more descriptive settings header mobile 2025-10-19 13:24:44 -07:00
mbecker20 7674269ce9 fix user dropdown not showing username mobile 2025-10-19 13:11:34 -07:00
mbecker20 3b511c5adc improve server terminal mobile responsiveness 2025-10-19 13:00:30 -07:00
mbecker20 87221a10e9 fix mobile ContainerTerminal responsiveness 2025-10-19 12:56:11 -07:00
mbecker20 450cb6a148 fix stack config files mobile responsiveness 2025-10-19 12:46:51 -07:00
mbecker20 f252cefb21 responsive server docker tab 2025-10-19 12:37:26 -07:00
mbecker20 7855e9d688 run dkf 2025-10-19 12:30:59 -07:00
mbecker20 feb263c15f more type safe tabs 2025-10-19 12:27:55 -07:00
mbecker20 4f8d1c22cc rest of tabs also use mobile friendly 2025-10-19 12:11:11 -07:00
mbecker20 60bd47834e deploy 2.0.0-dev-63 2025-10-19 11:48:09 -07:00
mbecker20 4d632a6b61 improve resources mobile tabs responsiveness 2025-10-19 11:47:47 -07:00
mbecker20 381dd76723 deploy 2.0.0-dev-62 2025-10-19 01:37:10 -07:00
mbecker20 077e28a5fe fix ConfigList too wide on mobile 2025-10-19 01:36:50 -07:00
mbecker20 6b02aaed7d hide core pubkey copy if origin not https 2025-10-19 01:28:45 -07:00
mbecker20 e466944c05 improve mobile settings view 2025-10-19 01:24:41 -07:00
mbecker20 8ff94b7465 deploy 2.0.0-dev-61 2025-10-19 00:35:26 -07:00
mbecker20 b17df5ed7b show host public ip 2025-10-19 00:34:52 -07:00
mbecker20 207dc30206 cli is distroless, no shell / update-ca-certificates 2025-10-18 22:12:44 -07:00
mbecker20 c3eb386bdb fix copy entrypoint 2025-10-18 22:07:16 -07:00
mbecker20 4279e46892 deploy 2.0.0-dev-60 2025-10-18 12:59:19 -07:00
mbecker20 8d3d2fee12 use entrypoint scripts to make update-ca-certificates consistent when using custom CMD 2025-10-18 12:58:55 -07:00
mbecker20 1df36c4266 deploy 2.0.0-dev-59 2025-10-18 11:36:07 -07:00
mbecker20 36f7ad33c7 core and periphery images auto run update-ca-certificates on start, only need to mount in. 2025-10-18 11:35:45 -07:00
mbecker20 ec34b2c139 deploy 2.0.0-dev-58 2025-10-18 11:02:11 -07:00
mbecker20 d14c28d1f2 new otel instrumentation 2025-10-18 11:01:47 -07:00
mbecker20 68f7a0e9ce all info menu to top of settings 2025-10-18 00:45:59 -07:00
mbecker20 50f0376f0a Add Core title and public key to top of Settings 2025-10-18 00:01:41 -07:00
mbecker20 bbd53747ad fix km ps -h description 2025-10-17 17:17:18 -07:00
mbecker20 6a2adf1f83 tweak logs 2025-10-16 01:06:37 -07:00
mbecker20 128b15b94f deploy 2.0.0-dev-57 2025-10-16 00:59:46 -07:00
mbecker20 8d74b377b7 more otel refinements 2025-10-16 00:59:20 -07:00
mbecker20 d7e972e5c6 stack ui doesn't show project missing when deploying 2025-10-15 23:49:26 -07:00
mbecker20 e5cb4aac5a Fix: Webhook triggered checks linked repo branch for build, stack, sync 2025-10-15 18:06:43 -07:00
mbecker20 d0f62f8326 rework tracing events / improve opentelemetry output 2025-10-15 01:41:18 -07:00
mbecker20 47c4091a4b onboarding key uses recognizable key 2025-10-14 16:57:35 -07:00
mbecker20 973480e2b3 remove all the unnecessary instrument debug 2025-10-14 00:33:53 -07:00
mbecker20 b9e1cc87d2 remove instrument from validate_cancel_repo_build 2025-10-13 23:52:55 -07:00
mbecker20 05d20c8603 deploy 2.0.0-dev-56 2025-10-13 22:05:07 -07:00
mbecker20 fe2d68a001 fix config loading 2025-10-13 22:04:42 -07:00
mbecker20 26fd5b2a6d deploy 2.0.0-dev-55 2025-10-13 20:30:40 -07:00
mbecker20 76457bcb61 apply env / shell interpolation as *final* config loading stage, to include env vars. 2025-10-13 20:26:13 -07:00
mbecker20 ebd2c2238d bump deps 2025-10-13 19:51:05 -07:00
mbecker20 b7fc1bef7b refine default env 2025-10-13 13:53:12 -07:00
mbecker20 50b9f2e1bf deploy 2.0.0-dev-54 2025-10-13 13:06:23 -07:00
mbecker20 41ce86f6ab deploy 2.0.0-dev-53 2025-10-12 20:00:47 -07:00
mbecker20 7a21c01e52 tweak 2025-10-12 19:59:09 -07:00
mbecker20 e63e282510 small clean up 2025-10-12 19:56:15 -07:00
mbecker20 5456b36c18 deploy 2.0.0-dev-52 2025-10-12 13:55:39 -07:00
mbecker20 fcfb58a7e9 periphery with server disabled can initialize core public key file 2025-10-12 13:55:15 -07:00
mbecker20 2203004a74 move periphery in memory state to state.rs 2025-10-12 13:15:52 -07:00
mbecker20 996fb49823 periphery server_enabled /version route 2025-10-12 12:56:29 -07:00
mbecker20 35d22c77a2 Core add non authed /version route 2025-10-12 12:55:14 -07:00
mbecker20 44ab89600f Simpllify Option + Result into one encoding layer 2025-10-12 03:24:00 -07:00
mbecker20 0900e48cb8 ntfy / pushover url interpolation 2025-10-12 01:34:07 -07:00
mbecker20 c530a46a27 deploy 2.0.0-dev-51 2025-10-12 01:09:35 -07:00
mbecker20 f69c8db3ea pass through whether Periphery docker daemon connection is ok 2025-10-12 01:08:45 -07:00
mbecker20 48f2f651e1 periphery runs with logs if couldn't connect to docker daemon 2025-10-12 01:05:20 -07:00
mbecker20 bdb5b4185e rename some websocket fields 2025-10-12 00:28:55 -07:00
mbecker20 42a7b8c19b move connection queries to periphery_client 2025-10-12 00:08:59 -07:00
mbecker20 ded17e4840 more encoding refine 2025-10-12 00:05:16 -07:00
mbecker20 80fb1e6889 more on encoding 2025-10-11 14:11:07 -07:00
mbecker20 1dc861f538 fix periphery keys init when config.private_key is not explicitly defined. 2025-10-11 12:00:29 -07:00
mbecker20 3da63395fd fix EncodedOption docs 2025-10-10 00:32:05 -07:00
mbecker20 c40cbc4d77 deploy 2.0.0-dev-50 2025-10-09 23:40:42 -07:00
mbecker20 05e352e88c attach working 2025-10-09 23:28:27 -07:00
mbecker20 5884c09fb8 fix fe 2025-10-09 22:05:36 -07:00
mbecker20 f8add38043 backend for container attach 2025-10-09 21:53:26 -07:00
mbecker20 501f734e8b deploy 2.0.0-dev-49 2025-10-09 20:13:17 -07:00
mbecker20 de62732ac8 bump jwt lib 2025-10-09 20:12:51 -07:00
mbecker20 bfa61058cd remove github only managed repo webhooks feature. Not well implemented or documented, also provider specific. 2025-10-09 20:06:06 -07:00
mbecker20 72ca6d9910 deploy 2.0.0-dev-48 2025-10-09 19:36:47 -07:00
mbecker20 4d1ac32ad3 clippy 2025-10-09 18:24:50 -07:00
mbecker20 927e5959fa move encoded message schemas between core / periphery into periphery_client 2025-10-09 18:23:44 -07:00
mbecker20 37ccc6e1ef isolate encoding out of transport 2025-10-09 18:11:49 -07:00
mbecker20 deaa8754f3 slowly better ergonomics 2025-10-09 17:29:05 -07:00
mbecker20 dd8ac67c72 clippy and fmt 2025-10-09 16:26:06 -07:00
mbecker20 be4457c9cf deploy 2.0.0-dev-47 2025-10-09 15:41:06 -07:00
mbecker20 1868421815 strictly typed transport bytes encoding 2025-10-09 15:40:42 -07:00
mbecker20 366f7a12b4 Enumerated transport message types 2025-10-08 20:36:16 -07:00
mbecker20 75119370df standardize key rotation with wrapper 2025-10-08 17:45:45 -07:00
mbecker20 9e85b9d4c8 deploy 2.0.0-dev-46 2025-10-08 03:59:22 -07:00
mbecker20 8afbbf23dc deploy 2.0.0-dev-45 2025-10-08 02:48:24 -07:00
mbecker20 770a1116a1 fix: RotateCoreKeys also needs to store the new keys in mem 2025-10-08 02:48:01 -07:00
mbecker20 0b4aebbc24 periphery refresh panics if server_enabled, and core public key fails to parse. 2025-10-08 02:32:52 -07:00
mbecker20 f1696e26e4 deploy 2.0.0-dev-44 2025-10-08 02:11:38 -07:00
mbecker20 1a7b682301 RotateCoreKeys api 2025-10-08 02:11:17 -07:00
mbecker20 b0110b05aa deploy 2.0.0-dev-43 2025-10-08 00:02:34 -07:00
mbecker20 561b490f26 write files potentially containing secrets as 0600 2025-10-07 23:59:53 -07:00
mbecker20 cac1f0b42e align server standard and monitoring tables 2025-10-07 19:41:57 -07:00
mbecker20 28886fb304 fix typos 2025-10-07 14:32:00 -07:00
mbecker20 fb84d4cf7d deploy 2.0.0-dev-42 2025-10-07 01:59:04 -07:00
mbecker20 31e9624556 auto_rotate_keys config 2025-10-07 01:58:13 -07:00
mbecker20 3864bb7115 onboarding key expiry view 2025-10-07 01:16:28 -07:00
mbecker20 cea8601246 remove deleted server from onboarding key copy server 2025-10-07 00:44:36 -07:00
mbecker20 a546364bf3 deploy 2.0.0-dev-41 2025-10-07 00:29:33 -07:00
mbecker20 c8c62ea562 core public keys improve refresh 2025-10-07 00:27:47 -07:00
mbecker20 845e8780c7 improve server stats UI 2025-10-06 23:45:26 -07:00
mbecker20 db60347566 deploy 2.0.0-dev-40 2025-10-06 22:12:40 -07:00
mbecker20 c3ea0239d6 fix passkey support 2025-10-06 22:12:15 -07:00
mbecker20 e9d13449bf improve ws trait ergonomics 2025-10-06 20:02:06 -07:00
mbecker20 2daa92a639 working with safer transport message api 2025-10-06 19:16:03 -07:00
mbecker20 6473080078 deploy 2.0.0-dev-39 2025-10-06 03:14:15 -07:00
mbecker20 d3957f65dc schedule alert send before not after 2025-10-06 03:13:48 -07:00
mbecker20 cb34969f1e move skip label to be built into images 2025-10-06 03:07:11 -07:00
mbecker20 55a0a8cd05 deploy 2.0.0-dev-38 2025-10-06 02:38:42 -07:00
mbecker20 89f08372c6 CloseAlert 2025-10-06 02:38:16 -07:00
mbecker20 6a3ce2d426 config log some errors 2025-10-06 02:13:36 -07:00
mbecker20 4928378d46 fmt 2025-10-06 02:03:03 -07:00
mbecker20 eea222cfba simplify periphery config by removing option 2025-10-06 02:02:31 -07:00
mbecker20 6e9cc2dc77 deploy 2.0.0-dev-37 2025-10-06 01:40:24 -07:00
mbecker20 55d45084d0 comment 2025-10-06 01:40:00 -07:00
mbecker20 9657a44049 Improve config toml / yaml / json interpolation support 2025-10-06 01:38:48 -07:00
mbecker20 51fa9ae3c2 update setup script readme 2025-10-06 00:29:35 -07:00
mbecker20 5fd256444e improve the setup script 2025-10-05 23:53:21 -07:00
mbecker20 059716f178 deploy 2.0.0-dev-36 2025-10-05 18:23:43 -07:00
mbecker20 0bee1fe2c5 fix: connect and connect insecure are swapped 2025-10-05 18:20:29 -07:00
mbecker20 1e58c1a958 deploy 2.0.0-dev-35 2025-10-05 17:45:16 -07:00
mbecker20 ed1431db0a improve v1 downgrade 2025-10-05 17:43:46 -07:00
mbecker20 dc769ff159 document periphery_public_key 2025-10-05 17:39:11 -07:00
mbecker20 098f23ac4c configure Core -> Periphery insecure_tls 2025-10-05 17:36:07 -07:00
mbecker20 03f577d22f forgiving periphery public key parsing 2025-10-05 17:02:08 -07:00
mbecker20 95ca217362 deploy 2.0.0-dev-34 2025-10-05 16:52:33 -07:00
mbecker20 6d61045764 support KOMODO_PERIPHERY_PUBLIC_KEY 2025-10-05 16:52:00 -07:00
mbecker20 34e075eaf3 periphery support core_tls_insecure_skip_verify 2025-10-05 16:12:04 -07:00
mbecker20 232dc0bb4e deploy 2.0.0-dev-33 2025-10-05 14:59:23 -07:00
mbecker20 0cc0ee2aab load periphery_public_key 2025-10-05 14:58:52 -07:00
mbecker20 edebe925ff add km maintenance tasks aliases 2025-10-05 14:50:20 -07:00
mbecker20 5fd45bbc7b deploy 2.0.0-dev-32 2025-10-05 14:39:09 -07:00
mbecker20 0a490dadb2 rotation maintenance execution doesn't make individual updates 2025-10-05 14:38:45 -07:00
mbecker20 23847c15bc deploy 2.0.0-dev-31 2025-10-05 14:21:18 -07:00
mbecker20 0d238aee4f onboarding create_builder 2025-10-05 14:20:58 -07:00
mbecker20 98ad6cf5fa create update use uppercase 2025-10-05 13:41:42 -07:00
mbecker20 e35b81630b deploy 2.0.0-dev-30 2025-10-05 13:30:47 -07:00
mbecker20 1215852fe4 onboarding set Server tags 2025-10-05 13:24:38 -07:00
mbecker20 4164b76ff5 onboarded server needs to be enabled 2025-10-05 12:36:04 -07:00
mbecker20 26a9daffeb deploy 2.0.0-dev-29 2025-10-05 05:49:29 -07:00
mbecker20 8bb9f16e9b onboarding save copy server selection 2025-10-05 05:47:51 -07:00
mbecker20 b6eaf76497 Include templates in onboarding selector 2025-10-05 05:44:58 -07:00
mbecker20 073893da0e deploy 2.0.0-dev-28 2025-10-05 05:18:48 -07:00
mbecker20 e71547f1c2 configure server onboarding key 2025-10-05 05:17:56 -07:00
mbecker20 1991627990 move periphery public key to Server info (keep it out of resource sync) 2025-10-05 04:18:59 -07:00
mbecker20 3434d827a3 deploy 2.0.0-dev-27 2025-10-05 02:57:58 -07:00
mbecker20 1ef8b9878a rotate all server keys task 2025-10-05 02:57:27 -07:00
mbecker20 07ddaa8377 tweak 2025-10-05 01:41:44 -07:00
mbecker20 142c08cde4 deploy 2.0.0-dev-26 2025-10-05 01:19:21 -07:00
mbecker20 1aa1422faa periphery private key rotation 2025-10-05 01:18:56 -07:00
mbecker20 1394e8a6b1 Rotate Server private keys 2025-10-05 00:54:56 -07:00
mbecker20 420ee10211 tweaks 2025-10-04 23:59:14 -07:00
mbecker20 e918461dc5 refine onboarding key 2025-10-04 23:36:37 -07:00
mbecker20 4dc9ca27be refactor Periphery onboarding 2025-10-04 16:43:02 -07:00
mbecker20 f49b186f2f consolidate periphery docker apis into single mod 2025-10-04 16:17:32 -07:00
mbecker20 6e039b41f1 deploy 2.0.0-dev-25 2025-10-03 17:51:46 -07:00
mbecker20 e7cd77b022 tweaks 2025-10-03 17:06:14 -07:00
mbecker20 556cbd04c7 server onboarding flow using onboarding key 2025-10-03 17:01:58 -07:00
mbecker20 4e3d181466 default documented setup now uses Periphery -> Core setup 2025-10-03 12:55:06 -07:00
mbecker20 5d4326f46f NOT_FOUND if server not found 2025-10-03 03:17:37 -07:00
mbecker20 4bb486ad0a deploy 2.0.0-dev-24 2025-10-03 02:30:20 -07:00
mbecker20 d29c5112d8 Confirm server public key flow 2025-10-03 02:29:53 -07:00
mbecker20 d41315b8a4 don't navigate to /login for network errors 2025-10-03 01:58:23 -07:00
mbecker20 847404388c deploy 2.0.0-dev-23 2025-10-03 00:48:11 -07:00
mbecker20 eef8ec59b8 deploy 2.0.0-dev-22 2025-10-03 00:19:43 -07:00
mbecker20 9eb32f9ff5 store attempted public keys 2025-10-03 00:13:55 -07:00
mbecker20 859bfe67ef Improve Core side connection handling and fix Periphery -> Core error report 2025-10-02 23:03:58 -07:00
mbecker20 21ea469cd4 add login message 2 sec timeout 2025-10-02 16:00:45 -07:00
mbecker20 7fb902b892 deploy 2.0.0-dev-21 2025-10-02 03:12:59 -07:00
mbecker20 c9c4ac47ee fix clippy 2025-10-02 02:34:23 -07:00
mbecker20 f228cd31f3 deploy 2.0.0-dev-20 2025-10-02 02:33:33 -07:00
mbecker20 4feecb4b97 write key pem files by default when not otherwise provided. 2025-10-02 02:32:13 -07:00
mbecker20 e2680d0942 fix deploy 2025-10-01 21:35:27 -07:00
mbecker20 7422c0730d deploy 2.0.0-dev-19 2025-10-01 21:27:59 -07:00
mbecker20 37ac0dc7e3 update deploy 2025-10-01 21:17:43 -07:00
mbecker20 dccaca1df4 make sure not a config file before include as compose file 2025-10-01 20:32:52 -07:00
mbecker20 886aea4c36 deploy 2.0.0-dev-18 2025-10-01 19:48:40 -07:00
mbecker20 cbca070bae load keys from files 2025-10-01 19:41:32 -07:00
mbecker20 b4bdd401f6 fix unneeded base64 prefix 2025-10-01 02:36:26 -07:00
mbecker20 e546166240 use pkcs8 and spki for private / public key encoding, matching openssl 2025-10-01 02:25:41 -07:00
mbecker20 21689ce0ad periphery support same key gen functions 2025-09-29 23:32:47 -07:00
mbecker20 941787db64 slack client 0.5.0 2025-09-29 12:38:39 -07:00
mbecker20 d4b1aacac3 comment out 2025-09-29 02:21:07 -07:00
mbecker20 30f89461bf deploy 2.0.0-dev-17 2025-09-29 00:57:19 -07:00
mbecker20 a42d1397e9 back to bullseye (for max GLIBC compatibility) 2025-09-29 00:56:19 -07:00
mbecker20 b29313c28f deploy 2.0.0-dev-16 2025-09-29 00:47:17 -07:00
mbecker20 08a246a90c bullseye -> trixie 2025-09-29 00:46:51 -07:00
mbecker20 1a08df28d0 docs and config clean up 2025-09-29 00:06:35 -07:00
mbecker20 a226ffc256 fix json config load from interpolated 2025-09-28 23:20:04 -07:00
mbecker20 b385ee5ec3 start on docs update 2025-09-28 22:59:58 -07:00
mbecker20 c78c34357d remove unnecessary connected to core websocket log 2025-09-28 18:14:57 -07:00
mbecker20 4b7c692f00 deploy 2.0.0-dev-15 2025-09-28 18:02:18 -07:00
mbecker20 1ac98a096e bump async timing util to 1.1.0 to support for timelengths 2025-09-28 17:57:12 -07:00
mbecker20 281a2dc1ce first server configuration works with Periphery -> Core 2025-09-28 14:39:11 -07:00
mbecker20 0fe91378a6 tweak key gen output 2025-09-28 14:12:41 -07:00
mbecker20 11e76d1cf2 deploy 2.0.0-dev-14 2025-09-28 13:10:00 -07:00
mbecker20 a3bcd71105 simplify cache refresh with single periphery call 2025-09-28 13:05:45 -07:00
mbecker20 3ecc56dd76 clean up crypto provider install 2025-09-27 21:40:20 -07:00
mbecker20 7239cbb19b remove extra install crypto provider 2025-09-27 19:37:50 -07:00
mbecker20 a0540f7011 deploy 2.0.0-dev-13 2025-09-27 16:54:00 -07:00
mbecker20 37aea7605e gen types 2025-09-27 14:33:14 -07:00
mbecker20 78be913541 fix stuff after main rebase 2025-09-27 14:26:58 -07:00
mbecker20 c34f5ebf49 update config and compose envs 2025-09-27 14:23:49 -07:00
mbecker20 e5822cefb8 clean up socket handling 2025-09-27 14:23:49 -07:00
mbecker20 4baab194cf centralize the terminal stuff 2025-09-27 14:23:49 -07:00
mbecker20 a896583da6 deploy 2.0.0-dev-12 2025-09-27 14:23:49 -07:00
mbecker20 7b2674c38b deploy 2.0.0-dev-11 2025-09-27 14:23:42 -07:00
mbecker20 d1e32989e3 allow any number of simultaneous inbound / outbound connections (to different Cores) 2025-09-27 14:23:36 -07:00
mbecker20 e802bb3882 periphery support multiple core_public_keys 2025-09-27 14:23:36 -07:00
mbecker20 27a38b1bf5 periphery support multiple simultaneous core connections 2025-09-27 14:23:36 -07:00
mbecker20 2bc8a754be clean up passkey login 2025-09-27 14:23:36 -07:00
mbecker20 7a2a54bec1 dev-10 2025-09-27 14:23:36 -07:00
mbecker20 6a15150d59 don't cleanup server type builders 2025-09-27 14:23:31 -07:00
mbecker20 1b1dca76da deploy 2.0.0-dev-9 2025-09-27 14:23:31 -07:00
mbecker20 a032f0f4ff move system info to server cache 2025-09-27 14:23:25 -07:00
mbecker20 2749d49435 Core -> Periphery connection prefers noise handshake if 'core_public_key' is set 2025-09-27 14:23:25 -07:00
mbecker20 d88e42ef2d add specific server passkey support back 2025-09-27 14:23:25 -07:00
mbecker20 a370e7d121 support passkey auth for Core -> Periphery connection to remove the breaking change 2025-09-27 14:23:25 -07:00
mbecker20 d139ad2b3d always fallback to core config 'periphery_public_key' 2025-09-27 14:23:25 -07:00
mbecker20 8d2d180398 deploy 2.0.0-dev-8 2025-09-27 14:22:48 -07:00
mbecker20 37ca4ca986 fix server update hang 2025-09-27 14:22:42 -07:00
mbecker20 33e73b8543 use warn log 2025-09-27 14:22:42 -07:00
mbecker20 cf6e36e90c periphery server avoid auth fail log spam 2025-09-27 14:22:42 -07:00
mbecker20 9eb8b32f4a create and delete connections on demand 2025-09-27 14:22:42 -07:00
mbecker20 b400add6f1 deploy 2.0.0-dev-7 2025-09-27 14:22:41 -07:00
mbecker20 24adb89d25 execute container exec waits a bit for terminal to init before sending command 2025-09-27 14:22:36 -07:00
mbecker20 4674b2badb deploy 2.0.0-dev-6 2025-09-27 14:22:36 -07:00
mbecker20 65d1a69cb9 Mount ExecuteContainerExec periphery api 2025-09-27 14:22:27 -07:00
mbecker20 0da5718991 store connection channels under the connection 2025-09-27 14:22:27 -07:00
mbecker20 6b26cd120c simplify most of periphery client into bin/core 2025-09-27 14:22:27 -07:00
mbecker20 28e1bb19a4 deploy 2.0.0-dev-5 2025-09-27 14:22:27 -07:00
mbecker20 166107ac07 bail_if_not_connected 2025-09-27 14:22:21 -07:00
mbecker20 d77201880f dashboard Active include GlobalAutoUpdate 2025-09-27 14:22:21 -07:00
mbecker20 1d7629e9b2 Update server address description and placeholders 2025-09-27 14:22:21 -07:00
mbecker20 198f690ca5 Got invalid public key: {public_key} 2025-09-27 14:22:21 -07:00
mbecker20 531c79a144 deploy 2.0.0-dev-4 2025-09-27 14:22:21 -07:00
mbecker20 d685862713 improve Core - Periphery auth error messages 2025-09-27 14:22:09 -07:00
mbecker20 af0f245b5b deploy 2.0.0-dev-3 2025-09-27 14:22:09 -07:00
mbecker20 cba36861b7 deploy 2.0.0-dev-2 2025-09-27 14:22:02 -07:00
mbecker20 2c2c1d47b4 dev-2 2025-09-27 14:22:02 -07:00
mbecker20 3a6b997241 Json and JsonPretty formatting 2025-09-27 14:21:54 -07:00
mbecker20 7122f79b9d add -f json option to key utils (for use with jquery etc. 2025-09-27 14:21:54 -07:00
mbecker20 9bcee8122b tweak 2025-09-27 14:21:54 -07:00
mbecker20 a49c98946e add copy pubkeys 2025-09-27 14:21:54 -07:00
mbecker20 7d222a7241 dev-1 2025-09-27 14:21:54 -07:00
mbecker20 33501dac3e fix Core -> Periphery reconnection 2025-09-27 14:21:44 -07:00
mbecker20 4675dfa736 improve the logging 2025-09-27 14:21:44 -07:00
mbecker20 0be51dc784 move core connection handlers into core binary 2025-09-27 14:21:44 -07:00
mbecker20 52453d1320 set default allowed periphery public key 2025-09-27 14:21:44 -07:00
mbecker20 25da97ac1a basic configure auth 2025-09-27 14:21:44 -07:00
mbecker20 02db5a11d3 pipe through core side private / public key handling 2025-09-27 14:21:44 -07:00
mbecker20 89a5272246 rename passkey -> private_key 2025-09-27 14:21:44 -07:00
mbecker20 ae51ea1ad6 Copy core public key 2025-09-27 14:21:44 -07:00
mbecker20 3bdb4bea16 Core includes public key in CoreInfo 2025-09-27 14:21:44 -07:00
mbecker20 677bb14b5d auth forward error 2025-09-27 14:21:44 -07:00
mbecker20 6700700a80 clean up websocket handlers with many params 2025-09-27 14:21:44 -07:00
mbecker20 996d4aa129 standardize server size header identifier extraction 2025-09-27 14:21:44 -07:00
mbecker20 75894a7282 wire through private keys 2025-09-27 14:21:44 -07:00
mbecker20 2a065edcf1 avoid looping periphery client error 2025-09-27 14:21:44 -07:00
mbecker20 6f3703acfb periphery client makes more sense 2025-09-27 14:21:44 -07:00
mbecker20 59e989ecdf noise library and cli key utilities 2025-09-27 14:21:44 -07:00
mbecker20 951ff34a9e abstract websocket handling implementations on both sides 2025-09-27 14:21:12 -07:00
mbecker20 2d83105500 clean up 2025-09-27 14:21:12 -07:00
mbecker20 3d455f5142 implement noise auth basic 2025-09-27 14:21:12 -07:00
mbecker20 01de8c4a9b use standardized websocket wrappers / traits 2025-09-27 14:21:12 -07:00
mbecker20 d5de338561 outbound connection mode working 2025-09-27 14:21:12 -07:00
mbecker20 58c1afb8ef add login draft for transport 2025-09-27 14:21:12 -07:00
mbecker20 230f357b5a everything over ws working 2025-09-27 14:21:12 -07:00
mbecker20 991c95fff0 execute basically working, still need to clear the response channel upon completion 2025-09-27 14:21:12 -07:00
mbecker20 f6243fe6b1 more cleanup 2025-09-27 14:21:12 -07:00
mbecker20 9feeccba6e container terminal over connection 2025-09-27 14:21:12 -07:00
mbecker20 673c7f3a6b multiplex requests + terminal over single WS 2025-09-27 14:21:12 -07:00
mbecker20 39f900d651 standardize and consolidate logic in transport lib 2025-09-27 14:21:12 -07:00
mbecker20 8a06a0d6ce is work 2025-09-27 14:21:12 -07:00
mbecker20 7789ee4f4a prog 2025-09-27 14:21:12 -07:00
mbecker20 0472b6a7f7 fix after 1.19.4 2025-09-27 14:21:12 -07:00
mbecker20 d1d2227d36 prog 2025-09-27 14:21:11 -07:00
mbecker20 cea7c5fc5e prog on ws connect 2025-09-27 14:21:11 -07:00
358 changed files with 9866 additions and 11015 deletions
+3 -9
View File
@@ -1,6 +1,6 @@
services:
dev:
image: mcr.microsoft.com/devcontainers/rust:1-bookworm
image: mcr.microsoft.com/devcontainers/rust:1-1-bullseye
volumes:
# Mount the root folder that contains .git
- ../:/workspace:cached
@@ -10,19 +10,13 @@ services:
- stacks:/etc/komodo/stacks
command: sleep infinity
ports:
- "9120:9120"
- "9121:9121"
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
# ...
@@ -36,4 +30,4 @@ volumes:
data:
repo-cache:
repos:
stacks:
stacks:
+3 -9
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": "22.12.0"
"version": "20.12.2"
},
"ghcr.io/devcontainers-community/features/deno:1": {
@@ -28,8 +28,7 @@
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
5173,
9120
9121
],
// Use 'postCreateCommand' to run commands after the container is created.
@@ -37,16 +36,11 @@
"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"
}
}
+1 -7
View File
@@ -1,9 +1,3 @@
#!/bin/sh
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
cargo install typeshare-cli
-56
View File
@@ -1,56 +0,0 @@
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
+107 -112
View File
@@ -82,9 +82,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "1.0.0"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -103,9 +103,9 @@ checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anstyle-parse"
version = "1.0.0"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
@@ -138,9 +138,9 @@ checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]]
name = "arc-swap"
version = "1.9.0"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6"
checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5"
dependencies = [
"rustversion",
]
@@ -324,9 +324,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ec2"
version = "1.220.1"
version = "1.216.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1065222c6fe7bed0ef49acf2bfdba8ab9b59cc14bc534772d575b365601cd557"
checksum = "0bcafb17cfb3978dbf5b5a637d101a6212bc080cb33b5881da65f87967aedf67"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -576,9 +576,9 @@ dependencies = [
[[package]]
name = "aws-smithy-types"
version = "1.4.7"
version = "1.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d73dbfbaa8e4bc57b9045137680b958d274823509a360abfd8e1d514d40c95c"
checksum = "d2b1117b3b2bbe166d11199b540ceed0d0f7676e36e7b962b5a437a9971eac75"
dependencies = [
"base64-simd",
"bytes",
@@ -653,7 +653,7 @@ dependencies = [
"sha1",
"sync_wrapper",
"tokio",
"tokio-tungstenite 0.28.0",
"tokio-tungstenite",
"tower",
"tower-layer",
"tower-service",
@@ -852,9 +852,9 @@ dependencies = [
[[package]]
name = "bollard"
version = "0.20.2"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4"
checksum = "227aa051deec8d16bd9c34605e7aaf153f240e35483dd42f6f78903847934738"
dependencies = [
"base64 0.22.1",
"bollard-stubs",
@@ -1064,9 +1064,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.6.0"
version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a"
dependencies = [
"clap_builder",
"clap_derive",
@@ -1074,9 +1074,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.6.0"
version = "4.5.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876"
dependencies = [
"anstream",
"anstyle",
@@ -1086,9 +1086,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.6.0"
version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
dependencies = [
"heck",
"proc-macro2",
@@ -1149,7 +1149,7 @@ dependencies = [
[[package]]
name = "command"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"komodo_client",
"shlex",
@@ -1489,7 +1489,7 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea"
[[package]]
name = "database"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"async-compression",
@@ -1759,7 +1759,7 @@ dependencies = [
[[package]]
name = "encoding"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"bytes",
@@ -1801,7 +1801,7 @@ dependencies = [
[[package]]
name = "environment"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"formatting",
@@ -1930,7 +1930,7 @@ dependencies = [
[[package]]
name = "formatting"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"mogh_error",
]
@@ -2109,7 +2109,7 @@ dependencies = [
[[package]]
name = "git"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"command",
@@ -2709,7 +2709,7 @@ dependencies = [
[[package]]
name = "interpolate"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"komodo_client",
@@ -2835,10 +2835,9 @@ dependencies = [
[[package]]
name = "komodo_cli"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"bcrypt",
"chrono",
"clap",
"colored",
@@ -2853,7 +2852,6 @@ dependencies = [
"mogh_logger",
"mogh_pki",
"mogh_secret_file",
"rustls 0.23.37",
"serde",
"serde_json",
"serde_qs",
@@ -2865,7 +2863,7 @@ dependencies = [
[[package]]
name = "komodo_client"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"async_timing_util",
@@ -2894,7 +2892,7 @@ dependencies = [
"strum 0.28.0",
"thiserror 2.0.18",
"tokio",
"tokio-tungstenite 0.29.0",
"tokio-tungstenite",
"tokio-util",
"tracing",
"typeshare",
@@ -2904,7 +2902,7 @@ dependencies = [
[[package]]
name = "komodo_core"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"arc-swap",
@@ -2962,7 +2960,7 @@ dependencies = [
"svi",
"tokio",
"tokio-util",
"toml",
"toml 1.0.4+spec-1.1.0",
"toml_pretty",
"tracing",
"transport",
@@ -2977,7 +2975,7 @@ dependencies = [
[[package]]
name = "komodo_periphery"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"arc-swap",
@@ -3226,9 +3224,9 @@ dependencies = [
[[package]]
name = "mogh_auth_server"
version = "1.2.13"
version = "1.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d649dff8bdacff15df7d65716fcc4e3b1643bbc970d609d31cb45b3e2e02b9ac"
checksum = "b5d93cfc5fd1041273091e6c55544a98df78497dd628503481d22cb676c90502"
dependencies = [
"anyhow",
"arc-swap",
@@ -3271,9 +3269,9 @@ dependencies = [
[[package]]
name = "mogh_config"
version = "1.0.5"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2f42709806fc4822dd9f116f68a43433ca89663e8e1842b6859faced1fc64c1"
checksum = "be34694a34d9b693db2db6b66c3a963c9ee77628b881801e20f110b771acf598"
dependencies = [
"colored",
"indexmap 2.13.0",
@@ -3282,7 +3280,7 @@ dependencies = [
"serde_json",
"serde_yaml_ng",
"thiserror 2.0.18",
"toml",
"toml 0.9.11+spec-1.1.0",
"wildcard",
]
@@ -3301,9 +3299,9 @@ dependencies = [
[[package]]
name = "mogh_logger"
version = "1.3.3"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0aac766e2f34066511e67bf330a88874a9ac9d58732c9c4eb0687546c7a206e"
checksum = "f5d0f4b7792da5b8a1786c451d8171fc6a9d7f02d4d59c6529ba353c36774d8d"
dependencies = [
"anyhow",
"opentelemetry",
@@ -3317,9 +3315,9 @@ dependencies = [
[[package]]
name = "mogh_pki"
version = "1.1.3"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "477508d50e1852afd8ed6b546c7cfbc95f6c7c26b9589f9f0f64dd36b5742436"
checksum = "3fcb4cbdee296a86d40a4a133717dbd10fc220e17f0631ec5960bc01f94d36c7"
dependencies = [
"anyhow",
"arc-swap",
@@ -3685,18 +3683,18 @@ dependencies = [
[[package]]
name = "objc2-core-foundation"
version = "0.3.2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
"bitflags 2.10.0",
]
[[package]]
name = "objc2-io-kit"
version = "0.3.2"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15"
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
dependencies = [
"libc",
"objc2-core-foundation",
@@ -3837,9 +3835,9 @@ dependencies = [
[[package]]
name = "opentelemetry-otlp"
version = "0.31.1"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f69cd6acbb9af919df949cd1ec9e5e7fdc2ef15d234b6b795aaa525cc02f71f"
checksum = "7a2366db2dca4d2ad033cad11e6ee42844fd727007af5ad04a1730f4cb8163bf"
dependencies = [
"http 1.4.0",
"opentelemetry",
@@ -4032,7 +4030,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]]
name = "periphery_client"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"encoding",
@@ -4229,9 +4227,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.106"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
dependencies = [
"unicode-ident",
]
@@ -4343,9 +4341,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.45"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
dependencies = [
"proc-macro2",
]
@@ -4993,9 +4991,9 @@ dependencies = [
[[package]]
name = "serde_qs"
version = "1.1.0"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c742cd44662647326f86b514eadcc227fff4ce684dbbdaf1943f758d5ea058c"
checksum = "ac22439301a0b6f45a037681518e3169e8db1db76080e2e9600a08d1027df037"
dependencies = [
"itoa",
"percent-encoding",
@@ -5016,9 +5014,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
version = "1.1.1"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
dependencies = [
"serde_core",
]
@@ -5377,9 +5375,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.117"
version = "2.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
dependencies = [
"proc-macro2",
"quote",
@@ -5408,9 +5406,9 @@ dependencies = [
[[package]]
name = "sysinfo"
version = "0.38.4"
version = "0.38.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f"
checksum = "d03c61d2a49c649a15c407338afe7accafde9dac869995dccb73e5f7ef7d9034"
dependencies = [
"libc",
"memchr",
@@ -5638,18 +5636,6 @@ 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",
@@ -5658,7 +5644,7 @@ dependencies = [
"rustls-pki-types",
"tokio",
"tokio-rustls 0.26.4",
"tungstenite 0.29.0",
"tungstenite",
]
[[package]]
@@ -5677,14 +5663,29 @@ dependencies = [
[[package]]
name = "toml"
version = "1.1.2+spec-1.1.0"
version = "0.9.11+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee"
checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
dependencies = [
"indexmap 2.13.0",
"serde_core",
"serde_spanned",
"toml_datetime",
"toml_datetime 0.7.5+spec-1.1.0",
"toml_parser",
"toml_writer",
"winnow",
]
[[package]]
name = "toml"
version = "1.0.4+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c94c3321114413476740df133f0d8862c61d87c8d26f04c6841e033c8c80db47"
dependencies = [
"indexmap 2.13.0",
"serde_core",
"serde_spanned",
"toml_datetime 1.0.0+spec-1.1.0",
"toml_parser",
"toml_writer",
"winnow",
@@ -5692,18 +5693,27 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
version = "0.7.5+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_datetime"
version = "1.0.0+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_parser"
version = "1.1.2+spec-1.1.0"
version = "1.0.9+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
dependencies = [
"winnow",
]
@@ -5722,9 +5732,9 @@ dependencies = [
[[package]]
name = "toml_writer"
version = "1.1.1+spec-1.1.0"
version = "1.0.6+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db"
checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
[[package]]
name = "tonic"
@@ -5767,9 +5777,9 @@ dependencies = [
[[package]]
name = "totp-rs"
version = "5.7.1"
version = "5.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2b36a9dd327e9f401320a2cb4572cc76ff43742bcfc3291f871691050f140ba"
checksum = "f124352108f58ef88299e909f6e9470f1cdc8d2a1397963901b4a6366206bf72"
dependencies = [
"base32",
"constant_time_eq",
@@ -5980,9 +5990,9 @@ dependencies = [
[[package]]
name = "tracing-subscriber"
version = "0.3.23"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"nu-ansi-term",
"serde",
@@ -5997,11 +6007,12 @@ dependencies = [
[[package]]
name = "transport"
version = "2.1.0"
version = "2.0.0-dev-123"
dependencies = [
"anyhow",
"axum",
"bytes",
"colored",
"data-encoding",
"encoding",
"futures-util",
@@ -6015,7 +6026,7 @@ dependencies = [
"sha1",
"sha2",
"tokio",
"tokio-tungstenite 0.29.0",
"tokio-tungstenite",
"tokio-util",
"tracing",
"url",
@@ -6033,23 +6044,6 @@ 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",
@@ -6061,6 +6055,7 @@ dependencies = [
"rustls-pki-types",
"sha1",
"thiserror 2.0.18",
"utf-8",
]
[[package]]
@@ -6264,13 +6259,13 @@ dependencies = [
[[package]]
name = "uuid"
version = "1.23.0"
version = "1.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb"
dependencies = [
"getrandom 0.4.1",
"js-sys",
"rand 0.10.0",
"rand 0.9.2",
"serde_core",
"wasm-bindgen",
]
@@ -7011,9 +7006,9 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
[[package]]
name = "winnow"
version = "1.0.0"
version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8"
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
[[package]]
name = "winreg"
+13 -13
View File
@@ -8,7 +8,7 @@ members = [
]
[workspace.package]
version = "2.1.0"
version = "2.0.0-dev-123"
edition = "2024"
authors = ["mbecker20 <becker.maxh@gmail.com>"]
license = "GPL-3.0-or-later"
@@ -37,19 +37,19 @@ 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.13"
mogh_auth_server = "1.2.11"
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.5"
mogh_logger = "1.3.3"
mogh_config = "1.0.2"
mogh_logger = "1.3.1"
mogh_server = "1.4.5"
toml_pretty = "2.0.0"
mogh_cache = "1.1.1"
mogh_pki = "1.1.3"
mogh_pki = "1.1.0"
mungos = "3.2.2"
svi = "1.2.0"
@@ -60,10 +60,10 @@ tokio-util = { version = "0.7.18", features = ["io", "codec"] }
tokio-stream = { version = "0.1.18", features = ["sync"] }
pin-project-lite = "0.2.17"
futures-util = "0.3.32"
arc-swap = "1.9.0"
arc-swap = "1.8.2"
# SERVER
tokio-tungstenite = { version = "0.29.0", features = ["rustls-tls-native-roots"] }
tokio-tungstenite = { version = "0.28.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 = "1.1.2"
toml = "1.0.4"
serde_yaml_ng = "0.10.0"
serde_json = "1.0.149"
serde_qs = "1.1.0"
serde_qs = "1.0.0"
url = "2.5.8"
# ERROR
@@ -96,7 +96,7 @@ dotenvy = "0.15.7"
envy = "0.4.2"
# CRYPTO / AUTH
uuid = { version = "1.23.0", features = ["v4", "fast-rng", "serde"] }
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"
@@ -112,13 +112,13 @@ hickory-resolver = "0.25.2"
portable-pty = "0.9.0"
shell-escape = "0.1.5"
crossterm = "0.29.0"
bollard = "0.20.2"
sysinfo = "0.38.4"
bollard = "0.20.1"
sysinfo = "0.38.3"
shlex = "1.3.0"
# CLOUD
aws-config = "1.8.15"
aws-sdk-ec2 = "1.220.1"
aws-sdk-ec2 = "1.216.0"
aws-credential-types = "1.2.14"
## CRON
+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.94.1-bookworm AS builder
FROM rust:1.93.1-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.94.1-bookworm AS chef
FROM lukemathwalker/cargo-chef:latest-rust-1.93.1-bookworm AS chef
WORKDIR /builder
# Plan just the RECIPE to see if things have changed
-2
View File
@@ -32,9 +32,7 @@ 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.94.1-bullseye AS builder
FROM rust:1.93.1-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:2
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
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:2
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries
-13
View File
@@ -1,13 +0,0 @@
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
@@ -1,101 +0,0 @@
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
@@ -1,13 +0,0 @@
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
}
}
}
@@ -1,46 +0,0 @@
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(())
}
+550 -131
View File
@@ -28,139 +28,558 @@ pub async fn handle(
}
println!("\n{}: Execution", "Mode".dimmed());
macro_rules! handle_execution {
(
execute: [$($ExecVariant:ident),* $(,)?],
batch: [$($BatchVariant:ident),* $(,)?],
) => {{
// Print data
match execution {
$(Execution::$ExecVariant(data) => println!("{}: {data:?}", "Data".dimmed()),)*
$(Execution::$BatchVariant(data) => println!("{}: {data:?}", "Data".dimmed()),)*
Execution::CommitSync(data) => println!("{}: {data:?}", "Data".dimmed()),
Execution::Sleep(data) => println!("{}: {data:?}", "Data".dimmed()),
Execution::None(data) => println!("{}: {data:?}", "Data".dimmed()),
}
$crate::command::wait_for_enter("run execution", yes)?;
info!("Running Execution...");
let client = $crate::command::komodo_client().await?;
// Execute and get result
match execution.clone() {
$(
Execution::$ExecVariant(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
)*
$(
Execution::$BatchVariant(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
)*
Execution::CommitSync(request) => client
.write(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::Sleep(request) => {
let duration =
Duration::from_millis(request.duration_ms as u64);
tokio::time::sleep(duration).await;
println!("Finished sleeping!");
std::process::exit(0)
}
Execution::None(_) => unreachable!(),
}
}};
match execution {
Execution::None(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RunAction(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchRunAction(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RunProcedure(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchRunProcedure(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RunBuild(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchRunBuild(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::CancelBuild(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::Deploy(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchDeploy(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PullDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StartDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RestartDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PauseDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::UnpauseDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StopDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DestroyDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchDestroyDeployment(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::CloneRepo(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchCloneRepo(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PullRepo(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchPullRepo(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BuildRepo(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchBuildRepo(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::CancelRepoBuild(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StartContainer(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RestartContainer(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PauseContainer(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::UnpauseContainer(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StopContainer(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DestroyContainer(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StartAllContainers(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RestartAllContainers(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PauseAllContainers(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::UnpauseAllContainers(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StopAllContainers(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PruneContainers(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DeleteNetwork(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PruneNetworks(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DeleteImage(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PruneImages(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DeleteVolume(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PruneVolumes(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PruneDockerBuilders(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PruneBuildx(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PruneSystem(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RunSync(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::CommitSync(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DeployStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchDeployStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DeployStackIfChanged(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchDeployStackIfChanged(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PullStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchPullStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StartStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RestartStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::PauseStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::UnpauseStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::StopStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::DestroyStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BatchDestroyStack(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RunStackService(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::TestAlerter(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::SendAlert(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RemoveSwarmNodes(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RemoveSwarmStacks(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RemoveSwarmServices(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::CreateSwarmConfig(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RotateSwarmConfig(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RemoveSwarmConfigs(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::CreateSwarmSecret(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RotateSwarmSecret(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RemoveSwarmSecrets(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::ClearRepoCache(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::BackupCoreDatabase(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::GlobalAutoUpdate(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RotateAllServerKeys(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::RotateCoreKeys(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
Execution::Sleep(data) => {
println!("{}: {data:?}", "Data".dimmed())
}
}
let res = handle_execution!(
execute: [
RunAction,
RunProcedure,
RunBuild,
CancelBuild,
Deploy,
PullDeployment,
StartDeployment,
RestartDeployment,
PauseDeployment,
UnpauseDeployment,
StopDeployment,
DestroyDeployment,
CloneRepo,
PullRepo,
BuildRepo,
CancelRepoBuild,
StartContainer,
RestartContainer,
PauseContainer,
UnpauseContainer,
StopContainer,
DestroyContainer,
StartAllContainers,
RestartAllContainers,
PauseAllContainers,
UnpauseAllContainers,
StopAllContainers,
PruneContainers,
DeleteNetwork,
PruneNetworks,
DeleteImage,
PruneImages,
DeleteVolume,
PruneVolumes,
PruneDockerBuilders,
PruneBuildx,
PruneSystem,
RunSync,
DeployStack,
DeployStackIfChanged,
PullStack,
StartStack,
RestartStack,
PauseStack,
UnpauseStack,
StopStack,
DestroyStack,
RunStackService,
TestAlerter,
SendAlert,
RemoveSwarmNodes,
UpdateSwarmNode,
RemoveSwarmStacks,
RemoveSwarmServices,
CreateSwarmConfig,
RotateSwarmConfig,
RemoveSwarmConfigs,
CreateSwarmSecret,
RotateSwarmSecret,
RemoveSwarmSecrets,
ClearRepoCache,
BackupCoreDatabase,
GlobalAutoUpdate,
RotateAllServerKeys,
RotateCoreKeys,
],
batch: [
BatchRunAction,
BatchRunProcedure,
BatchRunBuild,
BatchDeploy,
BatchDestroyDeployment,
BatchCloneRepo,
BatchPullRepo,
BatchBuildRepo,
BatchDeployStack,
BatchDeployStackIfChanged,
BatchPullStack,
BatchDestroyStack,
],
);
super::wait_for_enter("run execution", yes)?;
info!("Running Execution...");
let client = super::komodo_client().await?;
let res = match execution.clone() {
Execution::RunAction(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchRunAction(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::RunProcedure(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchRunProcedure(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::RunBuild(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchRunBuild(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::CancelBuild(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::Deploy(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchDeploy(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::PullDeployment(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::StartDeployment(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RestartDeployment(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PauseDeployment(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::UnpauseDeployment(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::StopDeployment(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::DestroyDeployment(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchDestroyDeployment(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::CloneRepo(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchCloneRepo(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::PullRepo(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchPullRepo(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::BuildRepo(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchBuildRepo(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::CancelRepoBuild(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::StartContainer(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RestartContainer(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PauseContainer(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::UnpauseContainer(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::StopContainer(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::DestroyContainer(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::StartAllContainers(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RestartAllContainers(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PauseAllContainers(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::UnpauseAllContainers(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::StopAllContainers(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PruneContainers(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::DeleteNetwork(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PruneNetworks(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::DeleteImage(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PruneImages(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::DeleteVolume(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PruneVolumes(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PruneDockerBuilders(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PruneBuildx(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PruneSystem(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RunSync(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::CommitSync(request) => client
.write(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::DeployStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchDeployStack(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::DeployStackIfChanged(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchDeployStackIfChanged(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::PullStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchPullStack(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::StartStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RestartStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::PauseStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::UnpauseStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::StopStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::DestroyStack(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BatchDestroyStack(request) => {
client.execute(request).await.map(ExecutionResult::Batch)
}
Execution::RunStackService(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::TestAlerter(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::SendAlert(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RemoveSwarmNodes(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RemoveSwarmStacks(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RemoveSwarmServices(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::CreateSwarmConfig(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RotateSwarmConfig(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RemoveSwarmConfigs(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::CreateSwarmSecret(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RotateSwarmSecret(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RemoveSwarmSecrets(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::ClearRepoCache(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::BackupCoreDatabase(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::GlobalAutoUpdate(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RotateAllServerKeys(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::RotateCoreKeys(request) => client
.execute(request)
.await
.map(|u| ExecutionResult::Single(u.into())),
Execution::Sleep(request) => {
let duration =
Duration::from_millis(request.duration_ms as u64);
tokio::time::sleep(duration).await;
println!("Finished sleeping!");
std::process::exit(0)
}
Execution::None(_) => unreachable!(),
};
match res {
Ok(ExecutionResult::Single(update)) => {
-2
View File
@@ -15,8 +15,6 @@ 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;
+42 -87
View File
@@ -2,7 +2,7 @@ use anyhow::{Context, anyhow};
use colored::Colorize;
use komodo_client::{
api::{
read::{GetServer, ListAllDockerContainers, ListServers},
read::{ListAllDockerContainers, ListServers},
terminal::InitTerminal,
},
entities::{
@@ -26,7 +26,7 @@ pub async fn handle_connect(
recreate,
}: &Connect,
) -> anyhow::Result<()> {
handle_terminal_forwarding(server, async {
handle_terminal_forwarding(async {
super::komodo_client()
.await?
.connect_server_terminal(
@@ -56,28 +56,25 @@ pub async fn handle_exec(
}: &Exec,
) -> anyhow::Result<()> {
let server = get_server(server.clone(), container).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
},
)
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
})
.await
}
@@ -89,28 +86,25 @@ pub async fn handle_attach(
}: &Attach,
) -> anyhow::Result<()> {
let server = get_server(server.clone(), container).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
},
)
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
})
.await
}
@@ -138,14 +132,11 @@ async fn get_server(
}
if containers.len() == 1 {
let server_id = containers
return containers
.pop()
.context("Shouldn't happen")?
.server_id
.context("Container doesn't have server_id")?;
let server_name =
client.read(GetServer { server: server_id }).await?.name;
return Ok(server_name);
.context("Container doesn't have server_id");
}
let servers = containers
@@ -172,7 +163,6 @@ 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
@@ -257,16 +247,6 @@ 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
{
@@ -317,31 +297,6 @@ 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")?;
-3
View File
@@ -264,9 +264,6 @@ pub fn cli_config() -> &'static CliConfig {
ansi: env
.komodo_cli_logging_ansi
.unwrap_or(config.cli_logging.ansi),
timestamps: env
.komodo_cli_logging_timestamps
.unwrap_or(config.cli_logging.timestamps),
otlp_endpoint: env
.komodo_cli_logging_otlp_endpoint
.unwrap_or(config.cli_logging.otlp_endpoint),
-7
View File
@@ -12,9 +12,6 @@ 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();
@@ -45,7 +42,6 @@ async fn app() -> anyhow::Result<()> {
}
Ok(())
}
args::Command::CoreInfo => command::core_info::handle().await,
args::Command::Container(container) => {
command::container::handle(container).await
}
@@ -56,9 +52,6 @@ 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.94.1-trixie AS core-builder
FROM rust:1.93.1-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:2
ARG UI_IMAGE=ghcr.io/moghtech/komodo-ui:2
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
ARG UI_IMAGE=ghcr.io/moghtech/komodo-ui:latest
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:2
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries
+30 -32
View File
@@ -20,14 +20,12 @@ 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
.as_ref()
.map(|e| format!("\n**error**: {e:#?}"))
.map(|e| format!("\n**error**: {e}"))
.unwrap_or_default();
format!(
"{level} | Swarm **{name}** is **unhealthy** ❌\n{link}{err}"
@@ -36,6 +34,28 @@ pub async fn send_alert(
_ => unreachable!(),
}
}
AlertData::ServerVersionMismatch {
id,
name,
region,
server_version,
core_version,
} => {
let region = fmt_region(region);
let link = resource_link(ResourceTargetVariant::Server, id);
match alert.level {
SeverityLevel::Ok => {
format!(
"{level} | **{name}**{region} | Periphery version now matches Core version ✅\n{link}"
)
}
_ => {
format!(
"{level} | **{name}**{region} | Version mismatch detected ⚠️\nPeriphery: **{server_version}** | Core: **{core_version}**\n{link}"
)
}
}
}
AlertData::ServerUnreachable {
id,
name,
@@ -62,28 +82,6 @@ pub async fn send_alert(
_ => unreachable!(),
}
}
AlertData::ServerVersionMismatch {
id,
name,
region,
server_version,
core_version,
} => {
let region = fmt_region(region);
let link = resource_link(ResourceTargetVariant::Server, id);
match alert.level {
SeverityLevel::Ok => {
format!(
"{level} | **{name}**{region} | Periphery version now matches Core version ✅\n{link}"
)
}
_ => {
format!(
"{level} | **{name}**{region} | Version mismatch detected ⚠️\nPeriphery: **{server_version}** | Core: **{core_version}**\n{link}"
)
}
}
}
AlertData::ServerCpu {
id,
name,
@@ -142,7 +140,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
String::new()
format!("")
};
format!(
"📦 Deployment **{name}** is now **{to}**{target}\nprevious: **{from}**\n{link}"
@@ -163,7 +161,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
String::new()
format!("")
};
format!(
"⬆ Deployment **{name}** has an update available{target}\nimage: **{image}**\n{link}"
@@ -184,7 +182,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
String::new()
format!("")
};
format!(
"⬆ Deployment **{name}** was updated automatically ⏫{target}\nimage: **{image}**\n{link}"
@@ -207,7 +205,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
String::new()
format!("")
};
format!(
"🥞 Stack **{name}** is now {to}{target}\nprevious: **{from}**\n{link}"
@@ -229,7 +227,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
String::new()
format!("")
};
format!(
"⬆ Stack **{name}** has an update available{target}\nservice: **{service}**\nimage: **{image}**\n{link}"
@@ -253,7 +251,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("\nserver: **{server}**")
} else {
String::new()
format!("")
};
format!(
"⬆ Stack **{name}** was updated automatically ⏫{target}\n{images_label}: **{images}**\n{link}"
+32 -34
View File
@@ -260,35 +260,9 @@ fn standard_alert_content(alert: &Alert) -> String {
SeverityLevel::Critical => {
let err = err
.as_ref()
.map(|e| format!("\nerror: {e:#?}"))
.map(|e| format!("\nerror: {e}"))
.unwrap_or_default();
format!(
"{level} | Swarm {name} is unhealthy ❌\n{link}{err}"
)
}
_ => unreachable!(),
}
}
AlertData::ServerUnreachable {
id,
name,
region,
err,
} => {
let region = fmt_region(region);
let link = resource_link(ResourceTargetVariant::Server, id);
match alert.level {
SeverityLevel::Ok => {
format!("{level} | {name}{region} is now connected\n{link}")
}
SeverityLevel::Critical => {
let err = err
.as_ref()
.map(|e| format!("\nerror: {e:#?}"))
.unwrap_or_default();
format!(
"{level} | {name}{region} is unreachable ❌\n{link}{err}"
)
format!("{level} | Swarm {name} is unhealthy ❌\n{link}{err}")
}
_ => unreachable!(),
}
@@ -315,6 +289,30 @@ fn standard_alert_content(alert: &Alert) -> String {
}
}
}
AlertData::ServerUnreachable {
id,
name,
region,
err,
} => {
let region = fmt_region(region);
let link = resource_link(ResourceTargetVariant::Server, id);
match alert.level {
SeverityLevel::Ok => {
format!("{level} | {name}{region} is now connected\n{link}")
}
SeverityLevel::Critical => {
let err = err
.as_ref()
.map(|e| format!("\nerror: {e:#?}"))
.unwrap_or_default();
format!(
"{level} | {name}{region} is unreachable ❌\n{link}{err}"
)
}
_ => unreachable!(),
}
}
AlertData::ServerCpu {
id,
name,
@@ -373,7 +371,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
String::new()
format!("")
};
format!(
"📦Deployment {name} is now {to_state}{target}\nprevious: {from}\n{link}",
@@ -394,7 +392,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
String::new()
format!("")
};
format!(
"⬆ Deployment {name} has an update available{target}\nimage: {image}\n{link}",
@@ -415,7 +413,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
String::new()
format!("")
};
format!(
"⬆ Deployment {name} was updated automatically{target}\nimage: {image}\n{link}",
@@ -438,7 +436,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
String::new()
format!("")
};
format!(
"🥞 Stack {name} is now {to_state}{target}\nprevious: {from}\n{link}",
@@ -460,7 +458,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
String::new()
format!("")
};
format!(
"⬆ Stack {name} has an update available{target}\nservice: {service}\nimage: {image}\n{link}",
@@ -484,7 +482,7 @@ fn standard_alert_content(alert: &Alert) -> String {
} else if let Some(server) = server_name {
format!("\nserver: {server}")
} else {
String::new()
format!("")
};
format!(
"⬆ Stack {name} was updated automatically ⏫{target}\n{images_label}: {images_str}\n{link}",
+36 -36
View File
@@ -42,7 +42,7 @@ pub async fn send_alert(
format!("{level} | Swarm *{name}* is *unhealthy* ❌");
let err = err
.as_ref()
.map(|e| format!("\nerror: {e:#?}"))
.map(|e| format!("\nerror: {e}"))
.unwrap_or_default();
let blocks = vec![
Block::header(level),
@@ -59,6 +59,35 @@ pub async fn send_alert(
_ => unreachable!(),
}
}
AlertData::ServerVersionMismatch {
id,
name,
region,
server_version,
core_version,
} => {
let region = fmt_region(region);
let text = match alert.level {
SeverityLevel::Ok => {
format!(
"{level} | *{name}*{region} | Periphery version now matches Core version ✅"
)
}
_ => {
format!(
"{level} | *{name}*{region} | Version mismatch detected ⚠️\nPeriphery: {server_version} | Core: {core_version}"
)
}
};
let blocks = vec![
Block::header(text.clone()),
Block::section(resource_link(
ResourceTargetVariant::Server,
id,
)),
];
(text, blocks.into())
}
AlertData::ServerUnreachable {
id,
name,
@@ -100,35 +129,6 @@ pub async fn send_alert(
_ => unreachable!(),
}
}
AlertData::ServerVersionMismatch {
id,
name,
region,
server_version,
core_version,
} => {
let region = fmt_region(region);
let text = match alert.level {
SeverityLevel::Ok => {
format!(
"{level} | *{name}*{region} | Periphery version now matches Core version ✅"
)
}
_ => {
format!(
"{level} | *{name}*{region} | Version mismatch detected ⚠️\nPeriphery: {server_version} | Core: {core_version}"
)
}
};
let blocks = vec![
Block::header(text.clone()),
Block::section(resource_link(
ResourceTargetVariant::Server,
id,
)),
];
(text, blocks.into())
}
AlertData::ServerCpu {
id,
name,
@@ -289,7 +289,7 @@ pub async fn send_alert(
} else if let Some(server) = server_name {
format!("server: *{server}*\n")
} else {
String::new()
format!("")
};
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 {
String::new()
format!("")
};
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 {
String::new()
format!("")
};
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 {
String::new()
format!("")
};
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 {
String::new()
format!("")
};
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 {
String::new()
format!("")
};
let blocks = vec![
Block::header(text.clone()),
+4 -8
View File
@@ -66,14 +66,14 @@ impl Resolve<ExecuteArgs> for BatchRunAction {
"BatchRunAction",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, 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(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
action = self.action,
@@ -95,11 +95,7 @@ impl Resolve<ExecuteArgs> for RunAction {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut action = get_check_permissions::<Action>(
&self.action,
+4 -12
View File
@@ -28,7 +28,7 @@ impl Resolve<ExecuteArgs> for TestAlerter {
"TestAlerter",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
alerter = self.alerter,
@@ -36,11 +36,7 @@ impl Resolve<ExecuteArgs> for TestAlerter {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let alerter = get_check_permissions::<Alerter>(
&self.alerter,
@@ -98,7 +94,7 @@ impl Resolve<ExecuteArgs> for SendAlert {
"SendAlert",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
request = format!("{self:?}"),
@@ -106,11 +102,7 @@ impl Resolve<ExecuteArgs> for SendAlert {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let alerters = list_full_for_user::<Alerter>(
Default::default(),
+7 -15
View File
@@ -75,14 +75,14 @@ impl Resolve<ExecuteArgs> for BatchRunBuild {
"BatchRunBuild",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, 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(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
build = self.build,
@@ -104,11 +104,7 @@ impl Resolve<ExecuteArgs> for RunBuild {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut build = get_check_permissions::<Build>(
&self.build,
@@ -526,7 +522,7 @@ impl Resolve<ExecuteArgs> for CancelBuild {
"CancelBuild",
skip(user, update),
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
build = self.build,
@@ -534,11 +530,7 @@ impl Resolve<ExecuteArgs> for CancelBuild {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let build = get_check_permissions::<Build>(
&self.build,
@@ -634,7 +626,7 @@ async fn handle_post_build_redeploy(build_id: &str) {
.resolve(&ExecuteArgs {
user,
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
}
+31 -63
View File
@@ -32,7 +32,7 @@ use crate::{
swarm::swarm_request,
update::update_update,
},
monitor::{refresh_server_cache, refresh_swarm_cache},
monitor::{update_cache_for_server, update_cache_for_swarm},
resource::{self, setup_deployment_execution},
state::action_states,
};
@@ -55,14 +55,14 @@ impl Resolve<ExecuteArgs> for BatchDeploy {
"BatchDeploy",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, 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(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -86,11 +86,7 @@ impl Resolve<ExecuteArgs> for Deploy {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (mut deployment, swarm_or_server) =
setup_deployment_execution(
@@ -226,7 +222,7 @@ impl Resolve<ExecuteArgs> for Deploy {
.await
{
Ok(logs) => {
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
update.logs.extend(logs)
}
Err(e) => {
@@ -250,7 +246,7 @@ impl Resolve<ExecuteArgs> for Deploy {
.await
{
Ok(log) => {
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.logs.push(log)
}
Err(e) => {
@@ -405,7 +401,7 @@ pub async fn pull_deployment_inner(
Err(e) => Log::error("Pull image", format_serror(&e.into())),
};
refresh_server_cache(server, true).await;
update_cache_for_server(server, true).await;
anyhow::Ok(log)
}
.await;
@@ -422,7 +418,7 @@ impl Resolve<ExecuteArgs> for PullDeployment {
"PullDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -430,11 +426,7 @@ impl Resolve<ExecuteArgs> for PullDeployment {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -480,7 +472,7 @@ impl Resolve<ExecuteArgs> for StartDeployment {
"StartDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -488,11 +480,7 @@ impl Resolve<ExecuteArgs> for StartDeployment {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -539,7 +527,7 @@ impl Resolve<ExecuteArgs> for StartDeployment {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -552,7 +540,7 @@ impl Resolve<ExecuteArgs> for RestartDeployment {
"RestartDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -560,11 +548,7 @@ impl Resolve<ExecuteArgs> for RestartDeployment {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -613,7 +597,7 @@ impl Resolve<ExecuteArgs> for RestartDeployment {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -626,7 +610,7 @@ impl Resolve<ExecuteArgs> for PauseDeployment {
"PauseDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -634,11 +618,7 @@ impl Resolve<ExecuteArgs> for PauseDeployment {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -685,7 +665,7 @@ impl Resolve<ExecuteArgs> for PauseDeployment {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -698,7 +678,7 @@ impl Resolve<ExecuteArgs> for UnpauseDeployment {
"UnpauseDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -706,11 +686,7 @@ impl Resolve<ExecuteArgs> for UnpauseDeployment {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -759,7 +735,7 @@ impl Resolve<ExecuteArgs> for UnpauseDeployment {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -772,7 +748,7 @@ impl Resolve<ExecuteArgs> for StopDeployment {
"StopDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -782,11 +758,7 @@ impl Resolve<ExecuteArgs> for StopDeployment {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -841,7 +813,7 @@ impl Resolve<ExecuteArgs> for StopDeployment {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -865,14 +837,14 @@ impl Resolve<ExecuteArgs> for BatchDestroyDeployment {
"BatchDestroyDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchDestroyDeployment>(
@@ -889,7 +861,7 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
"DestroyDeployment",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
deployment = self.deployment,
@@ -899,11 +871,7 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (deployment, swarm_or_server) = setup_deployment_execution(
&self.deployment,
@@ -942,7 +910,7 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
.await
{
Ok(log) => {
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
log
}
Err(e) => Log::error(
@@ -970,7 +938,7 @@ impl Resolve<ExecuteArgs> for DestroyDeployment {
.await
{
Ok(log) => {
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
log
}
Err(e) => Log::error(
+49 -111
View File
@@ -15,7 +15,7 @@ use komodo_client::{
},
entities::{
SwarmOrServer, deployment::DeploymentState, server::ServerState,
stack::StackState, swarm::SwarmState,
stack::StackState,
},
};
use mogh_error::AddStatusCodeError;
@@ -39,7 +39,7 @@ use crate::{
resource::rotate_server_keys,
state::{
db_client, deployment_status_cache, server_status_cache,
stack_status_cache, swarm_status_cache,
stack_status_cache,
},
};
@@ -54,18 +54,14 @@ impl Resolve<ExecuteArgs> for ClearRepoCache {
"ClearRepoCache",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id
)
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -137,18 +133,14 @@ impl Resolve<ExecuteArgs> for BackupCoreDatabase {
"BackupCoreDatabase",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
)
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -194,18 +186,14 @@ impl Resolve<ExecuteArgs> for GlobalAutoUpdate {
"GlobalAutoUpdate",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
)
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -244,7 +232,6 @@ impl Resolve<ExecuteArgs> for GlobalAutoUpdate {
.context("Failed to query for stacks from database")?;
let server_status_cache = server_status_cache();
let swarm_status_cache = swarm_status_cache();
let stack_status_cache = stack_status_cache();
// Will be edited later at update.logs[0]
@@ -256,7 +243,7 @@ impl Resolve<ExecuteArgs> for GlobalAutoUpdate {
continue;
};
// Only check running stacks.
// Only pull running stacks.
if !matches!(status.curr.state, StackState::Running) {
continue;
}
@@ -268,58 +255,43 @@ impl Resolve<ExecuteArgs> for GlobalAutoUpdate {
&servers,
)?;
// Ensure server / swarm is reachable
match &swarm_or_server {
SwarmOrServer::None => continue,
SwarmOrServer::Server(server) => {
if !server_status_cache
.get(&server.id)
.await
.map(|s| matches!(s.state, ServerState::Ok))
.unwrap_or_default()
{
continue;
}
}
SwarmOrServer::Swarm(swarm) => {
if !swarm_status_cache
.get(&swarm.id)
.await
.map(|s| {
matches!(
s.state,
SwarmState::Healthy | SwarmState::Unhealthy
)
})
.unwrap_or_default()
{
continue;
}
}
if let SwarmOrServer::None = &swarm_or_server {
continue;
}
if let Err(e) = check_stack_for_update_inner(
stack.id,
&swarm_or_server,
self.skip_auto_update,
true,
false,
)
.await
if let Some(server) =
servers.iter().find(|s| s.id == stack.config.server_id)
// This check is probably redundant along with running check
// but shouldn't hurt
&& server_status_cache
.get(&server.id)
.await
.map(|s| matches!(s.state, ServerState::Ok))
.unwrap_or_default()
{
update.push_error_log(
&format!("Check Stack {}", stack.name),
format_serror(&e.into()),
);
} else {
if !update.logs[0].stdout.is_empty() {
update.logs[0].stdout.push('\n');
}
if let Err(e) = check_stack_for_update_inner(
stack.id,
&swarm_or_server,
self.skip_auto_update,
true,
false,
)
.await
{
update.push_error_log(
&format!("Check Stack {}", stack.name),
format_serror(&e.into()),
);
} else {
if !update.logs[0].stdout.is_empty() {
update.logs[0].stdout.push('\n');
}
update.logs[0].stdout.push_str(&format!(
"Checked Stack {} ✅",
bold(&stack.name)
));
update.logs[0].stdout.push_str(&format!(
"Checked Stack {} ✅",
bold(&stack.name)
));
}
}
}
@@ -336,7 +308,7 @@ impl Resolve<ExecuteArgs> for GlobalAutoUpdate {
continue;
};
// Only check running deployments.
// Only pull running deployments.
if !matches!(status.curr.state, DeploymentState::Running) {
continue;
}
@@ -348,34 +320,8 @@ impl Resolve<ExecuteArgs> for GlobalAutoUpdate {
&servers,
)?;
// Ensure server / swarm is reachable
match &swarm_or_server {
SwarmOrServer::None => continue,
SwarmOrServer::Server(server) => {
if !server_status_cache
.get(&server.id)
.await
.map(|s| matches!(s.state, ServerState::Ok))
.unwrap_or_default()
{
continue;
}
}
SwarmOrServer::Swarm(swarm) => {
if !swarm_status_cache
.get(&swarm.id)
.await
.map(|s| {
matches!(
s.state,
SwarmState::Healthy | SwarmState::Unhealthy
)
})
.unwrap_or_default()
{
continue;
}
}
if let SwarmOrServer::None = &swarm_or_server {
continue;
}
let name = deployment.name.clone();
@@ -422,18 +368,14 @@ impl Resolve<ExecuteArgs> for RotateAllServerKeys {
"RotateAllServerKeys",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
)
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
@@ -540,7 +482,7 @@ impl Resolve<ExecuteArgs> for RotateCoreKeys {
"RotateCoreKeys",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
force = self.force,
@@ -548,11 +490,7 @@ impl Resolve<ExecuteArgs> for RotateCoreKeys {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
if !user.admin {
return Err(
+21 -52
View File
@@ -49,9 +49,9 @@ mod sync;
use super::Variant;
pub struct ExecuteArgs {
/// The task id.
/// Unique for every '/execute' call.
pub task_id: Uuid,
/// The execution id.
/// Unique for every /execute call.
pub 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(ExecuteRequestMethod), derive(Display))]
#[strum_discriminants(name(ExecuteRequestVariant), derive(Display))]
#[args(ExecuteArgs)]
#[response(JsonString)]
#[error(mogh_error::Error)]
@@ -148,7 +148,6 @@ pub enum ExecuteRequest {
// ==== SWARM ====
RemoveSwarmNodes(RemoveSwarmNodes),
UpdateSwarmNode(UpdateSwarmNode),
RemoveSwarmStacks(RemoveSwarmStacks),
RemoveSwarmServices(RemoveSwarmServices),
CreateSwarmConfig(CreateSwarmConfig),
@@ -250,19 +249,11 @@ pub fn inner_handler(
async move {
let log = match handle.await {
Ok(Err(e)) => {
warn!(
api = "Execute",
task_id = task_id.to_string(),
"/execute request task error: {e:#}",
);
warn!("/execute request {task_id} task error: {e:#}",);
Log::error("Task Error", format_serror(&e.into()))
}
Err(e) => {
warn!(
api = "Execute",
task_id = task_id.to_string(),
"/execute request spawn error: {e:?}",
);
warn!("/execute request {task_id} spawn error: {e:?}",);
Log::error("Spawn Error", format!("{e:#?}"))
}
_ => return,
@@ -277,7 +268,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
@@ -286,10 +277,7 @@ pub fn inner_handler(
if let Err(e) = res {
warn!(
api = "Execute",
task_id = task_id.to_string(),
update_id,
"Failed to modify Update with task error log | {e:#}"
"Failed to update update with task error log | {e:#}"
);
}
}
@@ -305,44 +293,25 @@ async fn task(
user: User,
update: Update,
) -> anyhow::Result<String> {
let method: ExecuteRequestMethod = (&request).into();
let user_id = user.id.clone();
let username = user.username.clone();
let variant: ExecuteRequestVariant = (&request).into();
info!(
api = "Execute",
task_id = id.to_string(),
method = method.to_string(),
user_id,
username,
"EXECUTE REQUEST",
"EXECUTE REQUEST {id} | METHOD: {variant} | USER: {} ({})",
user.username, user.id
);
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),
};
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),
};
if let Err(e) = &res {
warn!(
api = "Execute",
task_id = id.to_string(),
method = method.to_string(),
user_id,
username,
"EXECUTE REQUEST | ERROR: {e:#}"
);
warn!("EXECUTE REQUEST {id} | METHOD: {variant} | ERROR: {e:#}");
}
res
+2 -6
View File
@@ -59,7 +59,7 @@ impl Resolve<ExecuteArgs> for RunProcedure {
"RunProcedure",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
procedure = self.procedure,
@@ -67,11 +67,7 @@ impl Resolve<ExecuteArgs> for RunProcedure {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
Ok(
resolve_inner(self.procedure, user.clone(), update.clone())
+14 -30
View File
@@ -55,14 +55,14 @@ impl Resolve<ExecuteArgs> for BatchCloneRepo {
"BatchCloneRepo",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, 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(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -84,11 +84,7 @@ impl Resolve<ExecuteArgs> for CloneRepo {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut repo = get_check_permissions::<Repo>(
&self.repo,
@@ -190,14 +186,14 @@ impl Resolve<ExecuteArgs> for BatchPullRepo {
"BatchPullRepo",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchPullRepo>(&self.pattern, user)
@@ -211,7 +207,7 @@ impl Resolve<ExecuteArgs> for PullRepo {
"PullRepo",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -219,11 +215,7 @@ impl Resolve<ExecuteArgs> for PullRepo {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut repo = get_check_permissions::<Repo>(
&self.repo,
@@ -371,14 +363,14 @@ impl Resolve<ExecuteArgs> for BatchBuildRepo {
"BatchBuildRepo",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchBuildRepo>(&self.pattern, user)
@@ -392,7 +384,7 @@ impl Resolve<ExecuteArgs> for BuildRepo {
"BuildRepo",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -400,11 +392,7 @@ impl Resolve<ExecuteArgs> for BuildRepo {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let mut repo = get_check_permissions::<Repo>(
&self.repo,
@@ -717,7 +705,7 @@ impl Resolve<ExecuteArgs> for CancelRepoBuild {
"CancelRepoBuild",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
repo = self.repo,
@@ -725,11 +713,7 @@ impl Resolve<ExecuteArgs> for CancelRepoBuild {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let repo = get_check_permissions::<Repo>(
&self.repo,
+64 -148
View File
@@ -14,7 +14,7 @@ use periphery_client::api;
use crate::{
helpers::{periphery_client, update::update_update},
monitor::refresh_server_cache,
monitor::update_cache_for_server,
permission::get_check_permissions,
state::action_states,
};
@@ -26,7 +26,7 @@ impl Resolve<ExecuteArgs> for StartContainer {
"StartContainer",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -35,11 +35,7 @@ impl Resolve<ExecuteArgs> for StartContainer {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -80,7 +76,7 @@ impl Resolve<ExecuteArgs> for StartContainer {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -94,7 +90,7 @@ impl Resolve<ExecuteArgs> for RestartContainer {
"RestartContainer",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -103,11 +99,7 @@ impl Resolve<ExecuteArgs> for RestartContainer {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -150,7 +142,7 @@ impl Resolve<ExecuteArgs> for RestartContainer {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -164,7 +156,7 @@ impl Resolve<ExecuteArgs> for PauseContainer {
"PauseContainer",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -173,11 +165,7 @@ impl Resolve<ExecuteArgs> for PauseContainer {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -218,7 +206,7 @@ impl Resolve<ExecuteArgs> for PauseContainer {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -232,7 +220,7 @@ impl Resolve<ExecuteArgs> for UnpauseContainer {
"UnpauseContainer",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -241,11 +229,7 @@ impl Resolve<ExecuteArgs> for UnpauseContainer {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -288,7 +272,7 @@ impl Resolve<ExecuteArgs> for UnpauseContainer {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -302,7 +286,7 @@ impl Resolve<ExecuteArgs> for StopContainer {
"StopContainer",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -313,11 +297,7 @@ impl Resolve<ExecuteArgs> for StopContainer {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -360,7 +340,7 @@ impl Resolve<ExecuteArgs> for StopContainer {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -374,7 +354,7 @@ impl Resolve<ExecuteArgs> for DestroyContainer {
"DestroyContainer",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -385,11 +365,7 @@ impl Resolve<ExecuteArgs> for DestroyContainer {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let DestroyContainer {
server,
@@ -440,7 +416,7 @@ impl Resolve<ExecuteArgs> for DestroyContainer {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -454,7 +430,7 @@ impl Resolve<ExecuteArgs> for StartAllContainers {
"StartAllContainers",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -462,11 +438,7 @@ impl Resolve<ExecuteArgs> for StartAllContainers {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -505,7 +477,7 @@ impl Resolve<ExecuteArgs> for StartAllContainers {
);
}
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -518,7 +490,7 @@ impl Resolve<ExecuteArgs> for RestartAllContainers {
"RestartAllContainers",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -526,11 +498,7 @@ impl Resolve<ExecuteArgs> for RestartAllContainers {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -571,7 +539,7 @@ impl Resolve<ExecuteArgs> for RestartAllContainers {
);
}
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -584,7 +552,7 @@ impl Resolve<ExecuteArgs> for PauseAllContainers {
"PauseAllContainers",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -592,11 +560,7 @@ impl Resolve<ExecuteArgs> for PauseAllContainers {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -635,7 +599,7 @@ impl Resolve<ExecuteArgs> for PauseAllContainers {
);
}
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -648,7 +612,7 @@ impl Resolve<ExecuteArgs> for UnpauseAllContainers {
"UnpauseAllContainers",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -656,11 +620,7 @@ impl Resolve<ExecuteArgs> for UnpauseAllContainers {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -701,7 +661,7 @@ impl Resolve<ExecuteArgs> for UnpauseAllContainers {
);
}
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -714,7 +674,7 @@ impl Resolve<ExecuteArgs> for StopAllContainers {
"StopAllContainers",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -722,11 +682,7 @@ impl Resolve<ExecuteArgs> for StopAllContainers {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -765,7 +721,7 @@ impl Resolve<ExecuteArgs> for StopAllContainers {
);
}
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -778,7 +734,7 @@ impl Resolve<ExecuteArgs> for PruneContainers {
"PruneContainers",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -786,11 +742,7 @@ impl Resolve<ExecuteArgs> for PruneContainers {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -833,7 +785,7 @@ impl Resolve<ExecuteArgs> for PruneContainers {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -847,7 +799,7 @@ impl Resolve<ExecuteArgs> for DeleteNetwork {
"DeleteNetwork",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -856,11 +808,7 @@ impl Resolve<ExecuteArgs> for DeleteNetwork {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -898,7 +846,7 @@ impl Resolve<ExecuteArgs> for DeleteNetwork {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -912,7 +860,7 @@ impl Resolve<ExecuteArgs> for PruneNetworks {
"PruneNetworks",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -920,11 +868,7 @@ impl Resolve<ExecuteArgs> for PruneNetworks {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -965,7 +909,7 @@ impl Resolve<ExecuteArgs> for PruneNetworks {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -979,7 +923,7 @@ impl Resolve<ExecuteArgs> for DeleteImage {
"DeleteImage",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -988,11 +932,7 @@ impl Resolve<ExecuteArgs> for DeleteImage {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1027,7 +967,7 @@ impl Resolve<ExecuteArgs> for DeleteImage {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1041,7 +981,7 @@ impl Resolve<ExecuteArgs> for PruneImages {
"PruneImages",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1049,11 +989,7 @@ impl Resolve<ExecuteArgs> for PruneImages {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1092,7 +1028,7 @@ impl Resolve<ExecuteArgs> for PruneImages {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1106,7 +1042,7 @@ impl Resolve<ExecuteArgs> for DeleteVolume {
"DeleteVolume",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1115,11 +1051,7 @@ impl Resolve<ExecuteArgs> for DeleteVolume {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1157,7 +1089,7 @@ impl Resolve<ExecuteArgs> for DeleteVolume {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1171,7 +1103,7 @@ impl Resolve<ExecuteArgs> for PruneVolumes {
"PruneVolumes",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1179,11 +1111,7 @@ impl Resolve<ExecuteArgs> for PruneVolumes {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1222,7 +1150,7 @@ impl Resolve<ExecuteArgs> for PruneVolumes {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1236,7 +1164,7 @@ impl Resolve<ExecuteArgs> for PruneDockerBuilders {
"PruneDockerBuilders",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1244,11 +1172,7 @@ impl Resolve<ExecuteArgs> for PruneDockerBuilders {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1287,7 +1211,7 @@ impl Resolve<ExecuteArgs> for PruneDockerBuilders {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1301,7 +1225,7 @@ impl Resolve<ExecuteArgs> for PruneBuildx {
"PruneBuildx",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1309,11 +1233,7 @@ impl Resolve<ExecuteArgs> for PruneBuildx {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1352,7 +1272,7 @@ impl Resolve<ExecuteArgs> for PruneBuildx {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1366,7 +1286,7 @@ impl Resolve<ExecuteArgs> for PruneSystem {
"PruneSystem",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
server = self.server,
@@ -1374,11 +1294,7 @@ impl Resolve<ExecuteArgs> for PruneSystem {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let server = get_check_permissions::<Server>(
&self.server,
@@ -1416,7 +1332,7 @@ impl Resolve<ExecuteArgs> for PruneSystem {
};
update.logs.push(log);
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
+36 -76
View File
@@ -39,7 +39,7 @@ use crate::{
add_update_without_send, init_execution_update, update_update,
},
},
monitor::{refresh_server_cache, refresh_swarm_cache},
monitor::{update_cache_for_server, update_cache_for_swarm},
permission::get_check_permissions,
resource,
stack::{
@@ -69,14 +69,14 @@ impl Resolve<ExecuteArgs> for BatchDeployStack {
"BatchDeployStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, 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(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -100,11 +100,7 @@ impl Resolve<ExecuteArgs> for DeployStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (mut stack, swarm_or_server) = setup_stack_execution(
&self.stack,
@@ -317,10 +313,10 @@ impl Resolve<ExecuteArgs> for DeployStack {
match swarm_or_server {
SwarmOrServer::None => unreachable!(),
SwarmOrServer::Swarm(swarm) => {
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
SwarmOrServer::Server(server) => {
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
}
}
@@ -346,14 +342,14 @@ impl Resolve<ExecuteArgs> for BatchDeployStackIfChanged {
"BatchDeployStackIfChanged",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchDeployStackIfChanged>(
@@ -370,7 +366,7 @@ impl Resolve<ExecuteArgs> for DeployStackIfChanged {
"DeployStackIfChanged",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -379,11 +375,7 @@ impl Resolve<ExecuteArgs> for DeployStackIfChanged {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let stack = get_check_permissions::<Stack>(
&self.stack,
@@ -441,7 +433,7 @@ impl Resolve<ExecuteArgs> for DeployStackIfChanged {
.resolve(&ExecuteArgs {
user: user.clone(),
update,
task_id: *task_id,
id: *id,
})
.await
}
@@ -580,7 +572,7 @@ async fn deploy_services(
.resolve(&ExecuteArgs {
user: user.clone(),
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
}
@@ -611,7 +603,7 @@ async fn restart_services(
.resolve(&ExecuteArgs {
user: user.clone(),
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
}
@@ -774,14 +766,14 @@ impl Resolve<ExecuteArgs> for BatchPullStack {
"BatchPullStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
Ok(
super::batch_execute::<BatchPullStack>(&self.pattern, user)
@@ -886,7 +878,7 @@ pub async fn pull_stack_inner(
.await?;
// Ensure cached stack state up to date by updating server cache
refresh_server_cache(server, true).await;
update_cache_for_server(server, true).await;
Ok(res)
}
@@ -896,7 +888,7 @@ impl Resolve<ExecuteArgs> for PullStack {
"PullStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -905,11 +897,7 @@ impl Resolve<ExecuteArgs> for PullStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (stack, swarm_or_server) = setup_stack_execution(
&self.stack,
@@ -971,7 +959,7 @@ impl Resolve<ExecuteArgs> for StartStack {
"StartStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -980,11 +968,7 @@ impl Resolve<ExecuteArgs> for StartStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<StartStack>(
&self.stack,
@@ -1004,7 +988,7 @@ impl Resolve<ExecuteArgs> for RestartStack {
"RestartStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1013,11 +997,7 @@ impl Resolve<ExecuteArgs> for RestartStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<RestartStack>(
&self.stack,
@@ -1039,7 +1019,7 @@ impl Resolve<ExecuteArgs> for PauseStack {
"PauseStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1048,11 +1028,7 @@ impl Resolve<ExecuteArgs> for PauseStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<PauseStack>(
&self.stack,
@@ -1072,7 +1048,7 @@ impl Resolve<ExecuteArgs> for UnpauseStack {
"UnpauseStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1081,11 +1057,7 @@ impl Resolve<ExecuteArgs> for UnpauseStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<UnpauseStack>(
&self.stack,
@@ -1105,7 +1077,7 @@ impl Resolve<ExecuteArgs> for StopStack {
"StopStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1114,11 +1086,7 @@ impl Resolve<ExecuteArgs> for StopStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
execute_compose::<StopStack>(
&self.stack,
@@ -1150,14 +1118,14 @@ impl Resolve<ExecuteArgs> for BatchDestroyStack {
"BatchDestroyStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
pattern = self.pattern,
)
)]
async fn resolve(
self,
ExecuteArgs { user, task_id, .. }: &ExecuteArgs,
ExecuteArgs { user, id, .. }: &ExecuteArgs,
) -> mogh_error::Result<BatchExecutionResponse> {
super::batch_execute::<BatchDestroyStack>(&self.pattern, user)
.await
@@ -1170,7 +1138,7 @@ impl Resolve<ExecuteArgs> for DestroyStack {
"DestroyStack",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1181,11 +1149,7 @@ impl Resolve<ExecuteArgs> for DestroyStack {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (stack, swarm_or_server) = setup_stack_execution(
&self.stack,
@@ -1241,7 +1205,7 @@ impl Resolve<ExecuteArgs> for DestroyStack {
}
// Ensure cached stack state up to date by updating swarm cache
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
update.finalize();
update_update(update.clone()).await?;
@@ -1269,7 +1233,7 @@ impl Resolve<ExecuteArgs> for RunStackService {
"RunStackService",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
stack = self.stack,
@@ -1279,11 +1243,7 @@ impl Resolve<ExecuteArgs> for RunStackService {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let (mut stack, swarm_or_server) = setup_stack_execution(
&self.stack,
+33 -131
View File
@@ -1,6 +1,10 @@
use formatting::format_serror;
use komodo_client::{
api::execute::*,
api::execute::{
CreateSwarmConfig, CreateSwarmSecret, RemoveSwarmConfigs,
RemoveSwarmNodes, RemoveSwarmSecrets, RemoveSwarmServices,
RemoveSwarmStacks, RotateSwarmConfig, RotateSwarmSecret,
},
entities::{permission::PermissionLevel, swarm::Swarm},
};
use mogh_resolver::Resolve;
@@ -8,7 +12,7 @@ use mogh_resolver::Resolve;
use crate::{
api::execute::ExecuteArgs,
helpers::{swarm::swarm_request, update::update_update},
monitor::refresh_swarm_cache,
monitor::update_cache_for_swarm,
permission::get_check_permissions,
};
@@ -17,7 +21,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmNodes {
"RemoveSwarmNodes",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -27,11 +31,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmNodes {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -55,7 +55,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmNodes {
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Nodes",
@@ -72,78 +72,12 @@ impl Resolve<ExecuteArgs> for RemoveSwarmNodes {
}
}
impl Resolve<ExecuteArgs> for UpdateSwarmNode {
#[instrument(
"UpdateSwarmNode",
skip_all,
fields(
task_id = task_id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
node = self.node,
availability = format!("{:?}", self.availability),
label_add = format!("{:?}", self.label_add),
label_rm = format!("{:?}", self.label_rm),
role = format!("{:?}", self.role),
)
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
update_update(update.clone()).await?;
let mut update = update.clone();
match swarm_request(
&swarm.config.server_ids,
periphery_client::api::swarm::UpdateSwarmNode {
node: self.node,
availability: self.availability,
label_add: self.label_add,
label_rm: self.label_rm,
role: self.role,
},
)
.await
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Update Swarm Node",
format_serror(
&e.context("Failed to update swarm node").into(),
),
),
};
update.finalize();
update_update(update.clone()).await?;
Ok(update)
}
}
impl Resolve<ExecuteArgs> for RemoveSwarmStacks {
#[instrument(
"RemoveSwarmStacks",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -153,11 +87,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmStacks {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -181,7 +111,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmStacks {
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Stacks",
@@ -203,7 +133,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmServices {
"RemoveSwarmServices",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -212,11 +142,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmServices {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -239,7 +165,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmServices {
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Services",
@@ -261,7 +187,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmConfig {
"CreateSwarmConfig",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -270,11 +196,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmConfig {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -300,7 +222,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmConfig {
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Create Swarm Config",
@@ -322,7 +244,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmConfig {
"RotateSwarmConfig",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -331,11 +253,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmConfig {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -359,7 +277,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmConfig {
{
Ok(logs) => {
update.logs.extend(logs);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Rotate Swarm Config",
@@ -381,7 +299,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmConfigs {
"RemoveSwarmConfigs",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -390,11 +308,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmConfigs {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -417,7 +331,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmConfigs {
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Configs",
@@ -439,7 +353,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmSecret {
"CreateSwarmSecret",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -448,11 +362,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmSecret {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -479,7 +389,7 @@ impl Resolve<ExecuteArgs> for CreateSwarmSecret {
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Create Swarm Secret",
@@ -501,7 +411,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmSecret {
"RotateSwarmSecret",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -510,11 +420,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmSecret {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -538,7 +444,7 @@ impl Resolve<ExecuteArgs> for RotateSwarmSecret {
{
Ok(logs) => {
update.logs.extend(logs);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Rotate Swarm Secret",
@@ -560,7 +466,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmSecrets {
"RemoveSwarmSecrets",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
swarm = self.swarm,
@@ -569,11 +475,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmSecrets {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> Result<Self::Response, Self::Error> {
let swarm = get_check_permissions::<Swarm>(
&self.swarm,
@@ -596,7 +498,7 @@ impl Resolve<ExecuteArgs> for RemoveSwarmSecrets {
{
Ok(log) => {
update.logs.push(log);
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
Err(e) => update.push_error_log(
"Remove Swarm Secrets",
+182 -79
View File
@@ -21,7 +21,6 @@ use komodo_client::{
repo::Repo,
server::Server,
stack::Stack,
swarm::Swarm,
sync::ResourceSync,
update::{Log, Update},
user::sync_user,
@@ -54,7 +53,7 @@ impl Resolve<ExecuteArgs> for RunSync {
"RunSync",
skip_all,
fields(
task_id = task_id.to_string(),
id = id.to_string(),
operator = user.id,
update_id = update.id,
sync = self.sync,
@@ -64,11 +63,7 @@ impl Resolve<ExecuteArgs> for RunSync {
)]
async fn resolve(
self,
ExecuteArgs {
user,
update,
task_id,
}: &ExecuteArgs,
ExecuteArgs { user, update, id }: &ExecuteArgs,
) -> mogh_error::Result<Update> {
let RunSync {
sync,
@@ -139,36 +134,56 @@ impl Resolve<ExecuteArgs> for RunSync {
let Some(resource_type) = match_resource_type else {
return 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),
}
};
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),
}
// 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<_>>()
});
@@ -216,39 +231,136 @@ impl Resolve<ExecuteArgs> for RunSync {
let delete = sync.config.managed || sync.config.delete;
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 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()
};
let (
variables_to_create,
@@ -286,7 +398,6 @@ 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()
@@ -314,11 +425,7 @@ 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(
@@ -357,10 +464,6 @@ 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,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -121,7 +121,7 @@ impl RepoExecution for CloneRepo {
.resolve(&ExecuteArgs {
user,
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -145,7 +145,7 @@ impl RepoExecution for PullRepo {
.resolve(&ExecuteArgs {
user,
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -169,7 +169,7 @@ impl RepoExecution for BuildRepo {
.resolve(&ExecuteArgs {
user,
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -272,7 +272,7 @@ impl StackExecution for DeployStack {
.resolve(&ExecuteArgs {
user,
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -290,7 +290,7 @@ impl StackExecution for DeployStack {
.resolve(&ExecuteArgs {
user,
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
@@ -403,7 +403,7 @@ impl SyncExecution for RunSync {
.resolve(&ExecuteArgs {
user,
update,
task_id: Uuid::new_v4(),
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,
task_id: Uuid::new_v4(),
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,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
.map_err(|e| e.error)?;
-23
View File
@@ -222,31 +222,8 @@ 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
);
})
}
+5 -15
View File
@@ -70,7 +70,7 @@ pub struct ReadArgs {
#[derive(
Serialize, Deserialize, Debug, Clone, Resolve, EnumDiscriminants,
)]
#[strum_discriminants(name(ReadRequestMethod), derive(Display))]
#[strum_discriminants(name(ReadRequestVariant), derive(Display))]
#[args(ReadArgs)]
#[response(Response)]
#[error(mogh_error::Error)]
@@ -291,28 +291,18 @@ async fn handler(
Json(request): Json<ReadRequest>,
) -> mogh_error::Result<axum::response::Response> {
let req_id = Uuid::new_v4();
let method: ReadRequestMethod = (&request).into();
let user_id = user.id.clone();
let username = user.username.clone();
let variant: ReadRequestVariant = (&request).into();
trace!(
req_id = req_id.to_string(),
method = method.to_string(),
user_id,
username,
"READ REQUEST",
"READ REQUEST {req_id} | METHOD: {variant} | USER: {} ({})",
user.username, user.id
);
let res = request.resolve(&ReadArgs { user }).await;
if let Err(e) = &res {
trace!(
req_id = req_id.to_string(),
method = method.to_string(),
user_id,
username,
"READ REQUEST | ERROR: {:#}",
"READ REQUEST {req_id} | METHOD: {variant} | 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_deploys.is_empty()
if !(resource_sync.info.pending_deploy.to_deploy == 0
&& resource_sync.info.resource_updates.is_empty()
&& resource_sync.info.variable_updates.is_empty()
&& resource_sync.info.user_group_updates.is_empty())
+339 -119
View File
@@ -1,8 +1,5 @@
use anyhow::Context;
use database::{
bson::doc,
mungos::{find::find_collect, mongodb::options::FindOptions},
};
use database::mungos::find::find_collect;
use komodo_client::{
api::read::{
ExportAllResourcesToToml, ExportAllResourcesToTomlResponse,
@@ -41,45 +38,122 @@ 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?
};
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,
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)),
);
Ok(targets)
}
@@ -113,7 +187,6 @@ impl Resolve<ReadArgs> for ExportAllResourcesToToml {
targets,
user_groups,
include_variables: self.include_variables,
existing: self.existing,
}
.resolve(args)
.await
@@ -129,64 +202,131 @@ 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::Server(id) => {
convert_target!(id, Server, servers)
}
ResourceTarget::Swarm(id) => {
convert_target!(id, Swarm, swarms)
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,
))
}
ResourceTarget::Stack(id) => {
convert_target!(id, Stack, stacks)
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,
))
}
ResourceTarget::Deployment(id) => {
convert_target!(id, Deployment, deployments)
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,
))
}
ResourceTarget::Build(id) => {
convert_target!(id, Build, builds)
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,
))
}
ResourceTarget::Repo(id) => convert_target!(id, Repo, repos),
ResourceTarget::Procedure(id) => {
convert_target!(id, Procedure, procedures)
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,
));
}
ResourceTarget::Action(id) => {
convert_target!(id, Action, actions)
}
ResourceTarget::Builder(id) => {
convert_target!(id, Builder, builders)
}
ResourceTarget::Alerter(id) => {
convert_target!(id, Alerter, alerters)
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,
));
}
ResourceTarget::ResourceSync(id) => {
let mut sync = get_check_permissions::<ResourceSync>(
@@ -209,6 +349,36 @@ 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,
};
}
@@ -218,21 +388,18 @@ impl Resolve<ReadArgs> for ExportResourcesToToml {
.context("failed to add user groups")?;
if include_variables {
res.variables = find_collect(
&db_client().variables,
None,
FindOptions::builder().sort(doc! { "name": 1 }).build(),
)
.await
.context("failed to get variables from db")?
.into_iter()
.map(|mut variable| {
if !user.admin && variable.is_secret {
variable.value = "#".repeat(variable.value.len())
}
variable
})
.collect();
res.variables =
find_collect(&db_client().variables, None, None)
.await
.context("failed to get variables from db")?
.into_iter()
.map(|mut variable| {
if !user.admin && variable.is_secret {
variable.value = "#".repeat(variable.value.len())
}
variable
})
.collect();
}
let toml = serialize_resources_toml(res)
@@ -267,32 +434,85 @@ fn serialize_resources_toml(
) -> anyhow::Result<String> {
let mut toml = String::new();
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)?;
}
)*
};
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)?;
}
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() {
+1 -12
View File
@@ -71,20 +71,9 @@ 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,
filter,
None,
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>(
+8 -24
View File
@@ -54,7 +54,7 @@ pub struct WriteArgs {
#[derive(
Serialize, Deserialize, Debug, Clone, Resolve, EnumDiscriminants,
)]
#[strum_discriminants(name(WriteRequestMethod), derive(Display))]
#[strum_discriminants(name(WriteRequestVariant), derive(Display))]
#[args(WriteArgs)]
#[response(Response)]
#[error(mogh_error::Error)]
@@ -255,35 +255,19 @@ async fn task(
request: WriteRequest,
user: User,
) -> mogh_error::Result<axum::response::Response> {
let task_id = Uuid::new_v4();
let method: WriteRequestMethod = (&request).into();
let req_id = Uuid::new_v4();
let variant: WriteRequestVariant = (&request).into();
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",
);
}
info!(
"WRITE REQUEST {req_id} | METHOD: {variant} | USER: {} ({})",
user.username, user.id
);
let res = request.resolve(&WriteArgs { user }).await;
if let Err(e) = &res {
warn!(
task_id = task_id.to_string(),
method = method.to_string(),
user_id,
username,
"WRITE REQUEST | ERROR: {:#}",
"WRITE REQUEST {req_id} | METHOD: {variant} | ERROR: {:#}",
e.error
);
}
+5 -38
View File
@@ -15,10 +15,7 @@ use mogh_pki::EncodedKeyPair;
use mogh_resolver::Resolve;
use reqwest::StatusCode;
use crate::{
api::write::WriteArgs, helpers::query::get_all_tags,
state::db_client,
};
use crate::{api::write::WriteArgs, state::db_client};
//
@@ -56,21 +53,6 @@ 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,
@@ -78,8 +60,8 @@ impl Resolve<WriteArgs> for CreateOnboardingKey {
onboarded: Default::default(),
created_at: komodo_timestamp(),
expires: self.expires,
tags,
privileged: self.privileged,
tags: self.tags,
fix_existing_servers: self.fix_existing_servers,
copy_server: self.copy_server,
create_builder: self.create_builder,
};
@@ -157,26 +139,11 @@ 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(privileged) = self.privileged {
update.insert("privileged", privileged);
if let Some(fix_existing_servers) = self.fix_existing_servers {
update.insert("fix_existing_servers", fix_existing_servers);
}
if let Some(copy_server) = self.copy_server {
+4 -16
View File
@@ -563,16 +563,7 @@ impl Resolve<WriteArgs> for RefreshStackCache {
(services, Some(contents), Some(errors), None, None)
} else {
// 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,
)
(vec![], None, None, None, None)
}
} else if !repo_empty {
// ================
@@ -780,7 +771,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!(
@@ -870,7 +861,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)
@@ -939,10 +930,7 @@ pub async fn check_stack_for_update_inner(
.retain(|(stack_id, _)| stack_id != &stack.id)
.await;
let deploy_services = if stack.config.auto_update_all_services
// Swarm stacks don't support individual service deploy
|| !stack.config.swarm_id.is_empty()
{
let deploy_services = if stack.config.auto_update_all_services {
Vec::new()
} else {
services_with_update
+105 -46
View File
@@ -26,8 +26,7 @@ use komodo_client::{
repo::Repo,
server::Server,
stack::Stack,
swarm::Swarm,
sync::{ResourceSync, ResourceSyncInfo},
sync::{ResourceSync, ResourceSyncInfo, SyncDeployUpdate},
to_path_compatible_name,
update::{Log, Update},
user::sync_user,
@@ -516,20 +515,11 @@ 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(),
@@ -785,40 +775,110 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
let mut diffs = Vec::new();
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),
);
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?;
(diffs, deploy_updates)
} else {
Default::default()
(Vec::new(), SyncDeployUpdate::default())
};
let variable_updates = if sync.config.include_variables {
@@ -852,7 +912,7 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
let (
resource_updates,
(pending_deploys, pending_deploy_error),
deploy_updates,
variable_updates,
user_group_updates,
pending_error,
@@ -868,7 +928,7 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
};
let has_updates = !resource_updates.is_empty()
|| !pending_deploys.is_empty()
|| !deploy_updates.to_deploy == 0
|| !variable_updates.is_empty()
|| !user_group_updates.is_empty();
@@ -880,8 +940,7 @@ impl Resolve<WriteArgs> for RefreshResourceSyncPending {
remote_errors: sync.info.remote_errors,
pending_hash: sync.info.pending_hash,
pending_message: sync.info.pending_message,
pending_deploys,
pending_deploy_error,
pending_deploy: deploy_updates,
resource_updates,
variable_updates,
user_group_updates,
+15 -29
View File
@@ -3,12 +3,8 @@ use futures_util::{StreamExt as _, stream::FuturesUnordered};
use komodo_client::{
api::write::*,
entities::{
NoData,
deployment::Deployment,
permission::PermissionLevel,
server::Server,
stack::Stack,
terminal::{Terminal, TerminalTarget},
NoData, deployment::Deployment, permission::PermissionLevel,
server::Server, stack::Stack, terminal::TerminalTarget,
user::User,
},
};
@@ -51,35 +47,30 @@ impl Resolve<WriteArgs> for CreateTerminal {
async fn resolve(
self,
WriteArgs { user }: &WriteArgs,
) -> mogh_error::Result<Terminal> {
) -> mogh_error::Result<NoData> {
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
.map_err(Into::into)
create_server_terminal(self, server, user).await?;
}
TerminalTarget::Container { server, container } => {
create_container_terminal(self, server, container, user)
.await
.map_err(Into::into)
.await?;
}
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
.map_err(Into::into)
.await?;
}
TerminalTarget::Deployment { deployment } => {
create_deployment_terminal(self, deployment, user)
.await
.map_err(Into::into)
create_deployment_terminal(self, deployment, user).await?;
}
}
};
Ok(NoData {})
}
}
@@ -93,7 +84,7 @@ async fn create_server_terminal(
}: CreateTerminal,
server: String,
user: &User,
) -> anyhow::Result<Terminal> {
) -> anyhow::Result<()> {
let server = get_check_permissions::<Server>(
&server,
user,
@@ -103,7 +94,7 @@ async fn create_server_terminal(
let periphery = periphery_client(&server).await?;
let mut terminal = periphery
periphery
.request(api::terminal::CreateServerTerminal {
name,
command,
@@ -112,12 +103,7 @@ async fn create_server_terminal(
.await
.context("Failed to create Server Terminal on Periphery")?;
// Fix server terminal target with server id
terminal.target = TerminalTarget::Server {
server: Some(server.id),
};
Ok(terminal)
Ok(())
}
async fn create_container_terminal(
@@ -125,7 +111,7 @@ async fn create_container_terminal(
server: String,
container: String,
user: &User,
) -> anyhow::Result<Terminal> {
) -> anyhow::Result<()> {
let server = get_check_permissions::<Server>(
&server,
user,
@@ -141,7 +127,7 @@ async fn create_stack_service_terminal(
stack: String,
service: String,
user: &User,
) -> anyhow::Result<Terminal> {
) -> anyhow::Result<()> {
let (_, periphery, container) =
get_stack_service_periphery_container(&stack, &service, user)
.await?;
@@ -152,7 +138,7 @@ async fn create_deployment_terminal(
req: CreateTerminal,
deployment: String,
user: &User,
) -> anyhow::Result<Terminal> {
) -> anyhow::Result<()> {
let (_, periphery, container) =
get_deployment_periphery_container(&deployment, user).await?;
create_container_terminal_inner(req, &periphery, container).await
-15
View File
@@ -36,15 +36,6 @@ 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,
@@ -88,12 +79,6 @@ 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,
+5 -18
View File
@@ -5,7 +5,6 @@ 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,
@@ -129,26 +128,14 @@ async fn forward_ws_channel(
};
}
Ok(Err(e)) => {
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;
}
let _ = client_send
.send(ws::Message::text(format!("{e:#}")))
.await;
break;
}
Err(_) => {
let _ = client_send
.send(ws::Message::text("\r\n\nSTREAM EOF"))
.await;
let _ =
client_send.send(ws::Message::text("STREAM EOF")).await;
break;
}
}
+3 -4
View File
@@ -375,9 +375,6 @@ pub fn core_config() -> &'static CoreConfig {
.komodo_logging_location
.unwrap_or(config.logging.location),
ansi: env.komodo_logging_ansi.unwrap_or(config.logging.ansi),
timestamps: env
.komodo_logging_timestamps
.unwrap_or(config.logging.timestamps),
otlp_endpoint: env
.komodo_logging_otlp_endpoint
.unwrap_or(config.logging.otlp_endpoint),
@@ -406,7 +403,9 @@ 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),
-15
View File
@@ -1,7 +1,6 @@
use std::time::Duration;
use anyhow::{Context, anyhow};
use komodo_client::entities::server::Server;
use periphery_client::{
CONNECTION_RETRY_SECONDS, transport::LoginMessage,
};
@@ -19,7 +18,6 @@ use transport::{
use crate::{
config::{core_config, core_connection_query},
monitor::refresh_server_cache,
periphery::PeripheryClient,
state::periphery_connections,
};
@@ -48,7 +46,6 @@ impl PeripheryConnectionArgs<'_> {
let responses = connection.responses.clone();
let _id = id.clone();
tokio::spawn(async move {
loop {
let ws = tokio::select! {
@@ -97,18 +94,6 @@ 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
}
});
+8 -21
View File
@@ -1,4 +1,4 @@
use std::{str::FromStr, time::Duration};
use std::str::FromStr;
use anyhow::{Context, anyhow};
use axum::{
@@ -42,7 +42,6 @@ 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},
};
@@ -164,7 +163,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 { privileged_required: true },
public_key_validator: OnboardingKeyValidator { fix_existing_servers_required: true },
should_close: true
})
.await
@@ -202,13 +201,6 @@ 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
}))
}
@@ -235,7 +227,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 { privileged_required: true },
public_key_validator: OnboardingKeyValidator { fix_existing_servers_required: true },
should_close: true,
})
.await
@@ -307,13 +299,6 @@ async fn fix_server(
} else {
None
},
// Move address to external_address if not set.
// This helps preserve container port link behavior.
external_address: if !server.config.external_address.is_empty() {
Some(server.config.address)
} else {
None
},
..Default::default()
};
if !config.is_none() {
@@ -356,7 +341,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 { privileged_required: false },
public_key_validator: OnboardingKeyValidator { fix_existing_servers_required: false },
should_close: true
})
.await
@@ -520,7 +505,7 @@ async fn create_server_maybe_builder(
}
struct OnboardingKeyValidator {
privileged_required: bool,
fix_existing_servers_required: bool,
}
impl PublicKeyValidator for OnboardingKeyValidator {
@@ -542,7 +527,9 @@ impl PublicKeyValidator for OnboardingKeyValidator {
{
return Err(anyhow!("Onboarding key is invalid"));
}
if self.privileged_required && !onboarding_key.privileged {
if self.fix_existing_servers_required
&& !onboarding_key.fix_existing_servers
{
return Err(anyhow!(
"Onboarding key not able to fix existing servers"
));
+23 -23
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);
}
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),
} else {
let digest = swarm_or_server_request(
&swarm_or_server,
GetLatestImageDigest {
name: image.clone(),
account,
token,
},
)
.await;
.await?
.digest;
Ok(digest)
let digest = ImageDigest::new(image, &digest);
self
.0
.insert(
image,
(digest.clone(), komodo_timestamp() + 10 * 60 * 1_000),
)
.await;
Ok(digest)
}
}
}
File diff suppressed because it is too large Load Diff
+10 -9
View File
@@ -6,7 +6,7 @@ use komodo_client::{
permission::PermissionLevel,
server::Server,
stack::Stack,
terminal::{ContainerTerminalMode, Terminal, TerminalTarget},
terminal::{ContainerTerminalMode, 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: Some(terminal.clone()),
name: 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: Some(terminal.clone()),
name: 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: Some(terminal.clone()),
name: 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: Some(terminal.clone()),
name: 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<Terminal> {
) -> anyhow::Result<()> {
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,8 +265,9 @@ 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(
+457 -144
View File
@@ -123,151 +123,464 @@ pub async fn init_execution_update(
request: &ExecuteRequest,
user: &User,
) -> anyhow::Result<Update> {
macro_rules! init_execution_match {
(
resource: [$(($Variant:ident, $ResType:ident, $field:ident)),* $(,)?],
batch: [$($BatchVariant:ident),* $(,)?],
stack_service: [$(($StackVariant:ident, $ServiceOp:ident)),* $(,)?],
system: [$($SysVariant:ident),* $(,)?],
) => {
match &request {
$(
ExecuteRequest::$Variant(data) => (
Operation::$Variant,
ResourceTarget::$ResType(
resource::get::<$ResType>(&data.$field).await?.id,
),
),
)*
$(
ExecuteRequest::$BatchVariant(_data) => {
return Ok(Default::default());
}
)*
$(
ExecuteRequest::$StackVariant(data) => (
if !data.services.is_empty() {
Operation::$ServiceOp
} else {
Operation::$StackVariant
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
)*
// DeployStackIfChanged doesn't have a service variant
ExecuteRequest::DeployStackIfChanged(data) => (
Operation::DeployStack,
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
$(
ExecuteRequest::$SysVariant(_data) => {
(Operation::$SysVariant, ResourceTarget::system())
}
)*
}
};
}
let (operation, target) = match &request {
// Swarm
ExecuteRequest::RemoveSwarmNodes(data) => (
Operation::RemoveSwarmNodes,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::RemoveSwarmStacks(data) => (
Operation::RemoveSwarmStacks,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::RemoveSwarmServices(data) => (
Operation::RemoveSwarmServices,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::CreateSwarmConfig(data) => (
Operation::CreateSwarmConfig,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::RotateSwarmConfig(data) => (
Operation::RotateSwarmConfig,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::RemoveSwarmConfigs(data) => (
Operation::RemoveSwarmConfigs,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::CreateSwarmSecret(data) => (
Operation::CreateSwarmSecret,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::RotateSwarmSecret(data) => (
Operation::RotateSwarmSecret,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
ExecuteRequest::RemoveSwarmSecrets(data) => (
Operation::RemoveSwarmSecrets,
ResourceTarget::Swarm(
resource::get::<Swarm>(&data.swarm).await?.id,
),
),
let (operation, target) = init_execution_match!(
resource: [
// Swarm
(RemoveSwarmNodes, Swarm, swarm),
(UpdateSwarmNode, Swarm, swarm),
(RemoveSwarmStacks, Swarm, swarm),
(RemoveSwarmServices, Swarm, swarm),
(CreateSwarmConfig, Swarm, swarm),
(RotateSwarmConfig, Swarm, swarm),
(RemoveSwarmConfigs, Swarm, swarm),
(CreateSwarmSecret, Swarm, swarm),
(RotateSwarmSecret, Swarm, swarm),
(RemoveSwarmSecrets, Swarm, swarm),
// Server
(StartContainer, Server, server),
(RestartContainer, Server, server),
(PauseContainer, Server, server),
(UnpauseContainer, Server, server),
(StopContainer, Server, server),
(DestroyContainer, Server, server),
(StartAllContainers, Server, server),
(RestartAllContainers, Server, server),
(PauseAllContainers, Server, server),
(UnpauseAllContainers, Server, server),
(StopAllContainers, Server, server),
(PruneContainers, Server, server),
(DeleteNetwork, Server, server),
(PruneNetworks, Server, server),
(DeleteImage, Server, server),
(PruneImages, Server, server),
(DeleteVolume, Server, server),
(PruneVolumes, Server, server),
(PruneDockerBuilders, Server, server),
(PruneBuildx, Server, server),
(PruneSystem, Server, server),
// Deployment
(Deploy, Deployment, deployment),
(PullDeployment, Deployment, deployment),
(StartDeployment, Deployment, deployment),
(RestartDeployment, Deployment, deployment),
(PauseDeployment, Deployment, deployment),
(UnpauseDeployment, Deployment, deployment),
(StopDeployment, Deployment, deployment),
(DestroyDeployment, Deployment, deployment),
// Build
(RunBuild, Build, build),
(CancelBuild, Build, build),
// Repo
(CloneRepo, Repo, repo),
(PullRepo, Repo, repo),
(BuildRepo, Repo, repo),
(CancelRepoBuild, Repo, repo),
// Procedure
(RunProcedure, Procedure, procedure),
// Action
(RunAction, Action, action),
// Resource Sync
(RunSync, ResourceSync, sync),
// Stack (simple)
(RunStackService, Stack, stack),
// Alerter
(TestAlerter, Alerter, alerter),
],
batch: [
BatchDeploy,
BatchDestroyDeployment,
BatchRunBuild,
BatchCloneRepo,
BatchPullRepo,
BatchBuildRepo,
BatchRunProcedure,
BatchRunAction,
BatchDeployStack,
BatchDeployStackIfChanged,
BatchPullStack,
BatchDestroyStack,
],
stack_service: [
(DeployStack, DeployStackService),
(PullStack, PullStackService),
(StartStack, StartStackService),
(RestartStack, RestartStackService),
(PauseStack, PauseStackService),
(UnpauseStack, UnpauseStackService),
(StopStack, StopStackService),
(DestroyStack, DestroyStackService),
],
system: [
SendAlert,
ClearRepoCache,
BackupCoreDatabase,
GlobalAutoUpdate,
RotateAllServerKeys,
RotateCoreKeys,
],
);
// Server
ExecuteRequest::StartContainer(data) => (
Operation::StartContainer,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::RestartContainer(data) => (
Operation::RestartContainer,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PauseContainer(data) => (
Operation::PauseContainer,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::UnpauseContainer(data) => (
Operation::UnpauseContainer,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::StopContainer(data) => (
Operation::StopContainer,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::DestroyContainer(data) => (
Operation::DestroyContainer,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::StartAllContainers(data) => (
Operation::StartAllContainers,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::RestartAllContainers(data) => (
Operation::RestartAllContainers,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PauseAllContainers(data) => (
Operation::PauseAllContainers,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::UnpauseAllContainers(data) => (
Operation::UnpauseAllContainers,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::StopAllContainers(data) => (
Operation::StopAllContainers,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PruneContainers(data) => (
Operation::PruneContainers,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::DeleteNetwork(data) => (
Operation::DeleteNetwork,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PruneNetworks(data) => (
Operation::PruneNetworks,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::DeleteImage(data) => (
Operation::DeleteImage,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PruneImages(data) => (
Operation::PruneImages,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::DeleteVolume(data) => (
Operation::DeleteVolume,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PruneVolumes(data) => (
Operation::PruneVolumes,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PruneDockerBuilders(data) => (
Operation::PruneDockerBuilders,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PruneBuildx(data) => (
Operation::PruneBuildx,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
ExecuteRequest::PruneSystem(data) => (
Operation::PruneSystem,
ResourceTarget::Server(
resource::get::<Server>(&data.server).await?.id,
),
),
// Deployment
ExecuteRequest::Deploy(data) => (
Operation::Deploy,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::BatchDeploy(_data) => {
return Ok(Default::default());
}
ExecuteRequest::PullDeployment(data) => (
Operation::PullDeployment,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::StartDeployment(data) => (
Operation::StartDeployment,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::RestartDeployment(data) => (
Operation::RestartDeployment,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::PauseDeployment(data) => (
Operation::PauseDeployment,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::UnpauseDeployment(data) => (
Operation::UnpauseDeployment,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::StopDeployment(data) => (
Operation::StopDeployment,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::DestroyDeployment(data) => (
Operation::DestroyDeployment,
ResourceTarget::Deployment(
resource::get::<Deployment>(&data.deployment).await?.id,
),
),
ExecuteRequest::BatchDestroyDeployment(_data) => {
return Ok(Default::default());
}
// Build
ExecuteRequest::RunBuild(data) => (
Operation::RunBuild,
ResourceTarget::Build(
resource::get::<Build>(&data.build).await?.id,
),
),
ExecuteRequest::BatchRunBuild(_data) => {
return Ok(Default::default());
}
ExecuteRequest::CancelBuild(data) => (
Operation::CancelBuild,
ResourceTarget::Build(
resource::get::<Build>(&data.build).await?.id,
),
),
// Repo
ExecuteRequest::CloneRepo(data) => (
Operation::CloneRepo,
ResourceTarget::Repo(
resource::get::<Repo>(&data.repo).await?.id,
),
),
ExecuteRequest::BatchCloneRepo(_data) => {
return Ok(Default::default());
}
ExecuteRequest::PullRepo(data) => (
Operation::PullRepo,
ResourceTarget::Repo(
resource::get::<Repo>(&data.repo).await?.id,
),
),
ExecuteRequest::BatchPullRepo(_data) => {
return Ok(Default::default());
}
ExecuteRequest::BuildRepo(data) => (
Operation::BuildRepo,
ResourceTarget::Repo(
resource::get::<Repo>(&data.repo).await?.id,
),
),
ExecuteRequest::BatchBuildRepo(_data) => {
return Ok(Default::default());
}
ExecuteRequest::CancelRepoBuild(data) => (
Operation::CancelRepoBuild,
ResourceTarget::Repo(
resource::get::<Repo>(&data.repo).await?.id,
),
),
// Procedure
ExecuteRequest::RunProcedure(data) => (
Operation::RunProcedure,
ResourceTarget::Procedure(
resource::get::<Procedure>(&data.procedure).await?.id,
),
),
ExecuteRequest::BatchRunProcedure(_) => {
return Ok(Default::default());
}
// Action
ExecuteRequest::RunAction(data) => (
Operation::RunAction,
ResourceTarget::Action(
resource::get::<Action>(&data.action).await?.id,
),
),
ExecuteRequest::BatchRunAction(_) => {
return Ok(Default::default());
}
// Resource Sync
ExecuteRequest::RunSync(data) => (
Operation::RunSync,
ResourceTarget::ResourceSync(
resource::get::<ResourceSync>(&data.sync).await?.id,
),
),
// Stack
ExecuteRequest::DeployStack(data) => (
if !data.services.is_empty() {
Operation::DeployStackService
} else {
Operation::DeployStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::BatchDeployStack(_data) => {
return Ok(Default::default());
}
ExecuteRequest::DeployStackIfChanged(data) => (
Operation::DeployStack,
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::BatchDeployStackIfChanged(_data) => {
return Ok(Default::default());
}
ExecuteRequest::StartStack(data) => (
if !data.services.is_empty() {
Operation::StartStackService
} else {
Operation::StartStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::PullStack(data) => (
if !data.services.is_empty() {
Operation::PullStackService
} else {
Operation::PullStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::BatchPullStack(_data) => {
return Ok(Default::default());
}
ExecuteRequest::RestartStack(data) => (
if !data.services.is_empty() {
Operation::RestartStackService
} else {
Operation::RestartStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::PauseStack(data) => (
if !data.services.is_empty() {
Operation::PauseStackService
} else {
Operation::PauseStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::UnpauseStack(data) => (
if !data.services.is_empty() {
Operation::UnpauseStackService
} else {
Operation::UnpauseStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::StopStack(data) => (
if !data.services.is_empty() {
Operation::StopStackService
} else {
Operation::StopStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::DestroyStack(data) => (
if !data.services.is_empty() {
Operation::DestroyStackService
} else {
Operation::DestroyStack
},
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
ExecuteRequest::BatchDestroyStack(_data) => {
return Ok(Default::default());
}
ExecuteRequest::RunStackService(data) => (
Operation::RunStackService,
ResourceTarget::Stack(
resource::get::<Stack>(&data.stack).await?.id,
),
),
// Alerter
ExecuteRequest::TestAlerter(data) => (
Operation::TestAlerter,
ResourceTarget::Alerter(
resource::get::<Alerter>(&data.alerter).await?.id,
),
),
ExecuteRequest::SendAlert(_) => {
(Operation::SendAlert, ResourceTarget::system())
}
// Maintenance
ExecuteRequest::ClearRepoCache(_data) => {
(Operation::ClearRepoCache, ResourceTarget::system())
}
ExecuteRequest::BackupCoreDatabase(_data) => {
(Operation::BackupCoreDatabase, ResourceTarget::system())
}
ExecuteRequest::GlobalAutoUpdate(_data) => {
(Operation::GlobalAutoUpdate, ResourceTarget::system())
}
ExecuteRequest::RotateAllServerKeys(_data) => {
(Operation::RotateAllServerKeys, ResourceTarget::system())
}
ExecuteRequest::RotateCoreKeys(_data) => {
(Operation::RotateCoreKeys, ResourceTarget::system())
}
};
let mut update = make_update(target, operation, user);
update.in_progress();
+1 -2
View File
@@ -3,8 +3,7 @@ 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::{
+1 -3
View File
@@ -2,9 +2,7 @@ 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;
+62 -162
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 alerts_to_close = Vec::<(Alert, SendAlerts)>::new();
let mut alert_ids_to_close = Vec::<(Alert, SendAlerts)>::new();
let buffer = alert_buffer();
@@ -66,21 +66,15 @@ 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,
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
match (server_status.state, health_alert) {
(ServerState::NotOk, None) => {
// Only open unreachable alert if not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -105,14 +99,19 @@ pub async fn alert_servers(
.push((alert, server.config.send_unreachable_alerts))
}
}
(ServerState::NotOk, Some(alert), true) => {
(ServerState::NotOk, Some(alert)) => {
// update alert err
let mut alert = alert.clone();
let (id, name, region) = match alert.data {
AlertData::ServerUnreachable {
id, name, region, ..
} => (id, name, region),
_ => unreachable!(),
data => {
error!(
"got incorrect alert data in ServerStatus handler. got {data:?}"
);
continue;
}
};
alert.data = AlertData::ServerUnreachable {
id,
@@ -125,30 +124,23 @@ pub async fn alert_servers(
alerts_to_update.push((alert, false));
}
(ServerState::NotOk, Some(alert), false) => {
alerts_to_close.push((
alert.clone(),
server.config.send_unreachable_alerts,
));
}
// Close an open alert
(ServerState::Ok | ServerState::Disabled, Some(alert), _) => {
alerts_to_close.push((
(ServerState::Ok | ServerState::Disabled, Some(alert)) => {
alert_ids_to_close.push((
alert.clone(),
server.config.send_unreachable_alerts,
));
}
(ServerState::Ok | ServerState::Disabled, None, _) => buffer
(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 {
@@ -166,14 +158,9 @@ pub async fn alert_servers(
alerts.get(&AlertDataVariant::ServerVersionMismatch)
});
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
match (mismatched_server_version, version_alert) {
(Some(version), None) => {
// Only open version mismatch alert if not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -200,47 +187,27 @@ pub async fn alert_servers(
.push((alert, server.config.send_version_mismatch_alerts))
}
}
(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));
}
(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(_), Some(alert), false) => {
alerts_to_close.push((
alert.clone(),
server.config.send_version_mismatch_alerts,
));
}
(None, Some(alert), _) => {
(None, Some(alert)) => {
// Version is now correct, close the alert
alerts_to_close.push((
alert_ids_to_close.push((
alert.clone(),
server.config.send_version_mismatch_alerts,
));
}
(None, None, _) => {
(None, None) => {
// Reset buffer state when no mismatch and no alert
buffer.reset(
server_status.id.clone(),
@@ -260,25 +227,10 @@ 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,
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
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
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -310,7 +262,6 @@ 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 {
@@ -329,15 +280,8 @@ pub async fn alert_servers(
.push((alert, server.config.send_cpu_alerts));
}
}
(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(alert),
_,
false,
) => {
alerts_to_close.push((alert, server.config.send_cpu_alerts));
}
(SeverityLevel::Ok, Some(mut alert), true, _) => {
(SeverityLevel::Ok, Some(alert), true) => {
let mut alert = alert.clone();
alert.data = AlertData::ServerCpu {
id: server_status.id.clone(),
name: server.name.clone(),
@@ -348,9 +292,10 @@ pub async fn alert_servers(
.map(|s| s.cpu_perc as f64)
.unwrap_or(0.0),
};
alerts_to_close.push((alert, server.config.send_cpu_alerts))
alert_ids_to_close
.push((alert, server.config.send_cpu_alerts))
}
(SeverityLevel::Ok, _, _, _) => buffer
(SeverityLevel::Ok, _, _) => buffer
.reset(server_status.id.clone(), AlertDataVariant::ServerCpu),
}
@@ -361,25 +306,10 @@ 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,
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
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
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -416,7 +346,6 @@ 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 {
@@ -440,16 +369,7 @@ pub async fn alert_servers(
.push((alert, server.config.send_mem_alerts));
}
}
(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(alert),
_,
false,
) => {
alerts_to_close
.push((alert.clone(), server.config.send_mem_alerts));
}
(SeverityLevel::Ok, Some(alert), true, _) => {
(SeverityLevel::Ok, Some(alert), true) => {
let mut alert = alert.clone();
alert.data = AlertData::ServerMem {
id: server_status.id.clone(),
@@ -466,9 +386,10 @@ pub async fn alert_servers(
.map(|s| s.mem_used_gb)
.unwrap_or(0.0),
};
alerts_to_close.push((alert, server.config.send_mem_alerts))
alert_ids_to_close
.push((alert, server.config.send_mem_alerts))
}
(SeverityLevel::Ok, _, _, _) => buffer
(SeverityLevel::Ok, _, _) => buffer
.reset(server_status.id.clone(), AlertDataVariant::ServerMem),
}
@@ -484,25 +405,13 @@ pub async fn alert_servers(
.as_ref()
.and_then(|alerts| alerts.get(path))
.cloned();
match (
health.level,
disk_alert,
health.should_close_alert,
server.config.send_disk_alerts,
) {
match (health.level, disk_alert, health.should_close_alert) {
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
false,
) => {}
(
SeverityLevel::Warning | SeverityLevel::Critical,
None,
_,
true,
) => {
// Only open disk alert if disk alerts enabled and not in maintenance and buffer is ready
// Only open disk alert if not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
server_status.id.clone(),
@@ -541,7 +450,6 @@ 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 {
@@ -562,16 +470,8 @@ pub async fn alert_servers(
.push((alert, server.config.send_disk_alerts));
}
}
(
SeverityLevel::Warning | SeverityLevel::Critical,
Some(alert),
_,
false,
) => {
alerts_to_close
.push((alert, server.config.send_disk_alerts));
}
(SeverityLevel::Ok, Some(mut alert), true, _) => {
(SeverityLevel::Ok, Some(alert), true) => {
let mut alert = alert.clone();
let disk =
server_status.system_stats.as_ref().and_then(|stats| {
stats.disks.iter().find(|disk| disk.mount == *path)
@@ -585,10 +485,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(),
};
alerts_to_close
alert_ids_to_close
.push((alert, server.config.send_disk_alerts))
}
(SeverityLevel::Ok, _, _, _) => buffer.reset(
(SeverityLevel::Ok, _, _) => buffer.reset(
server_status.id.clone(),
AlertDataVariant::ServerDisk,
),
@@ -601,7 +501,7 @@ pub async fn alert_servers(
if !health.disks.contains_key(path) {
let mut alert = alert.clone();
alert.level = SeverityLevel::Ok;
alerts_to_close
alert_ids_to_close
.push((alert, server.config.send_disk_alerts));
}
}
@@ -611,7 +511,7 @@ pub async fn alert_servers(
tokio::join!(
open_new_alerts(&alerts_to_open),
update_alerts(&alerts_to_update),
resolve_alerts(&alerts_to_close),
resolve_alerts(&alert_ids_to_close),
);
}
+3 -1
View File
@@ -64,7 +64,9 @@ 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)
+7 -31
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 alerts_to_close = Vec::<(Alert, SendAlerts)>::new();
let mut alert_ids_to_close = Vec::<(Alert, SendAlerts)>::new();
let buffer = alert_buffer();
@@ -68,26 +68,14 @@ 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,
swarm.config.send_unhealthy_alerts,
) {
match (swarm_status.state, health_alert) {
(
SwarmState::Unhealthy
| SwarmState::Down
| SwarmState::Unknown,
None,
false,
) => {}
(
SwarmState::Unhealthy
| SwarmState::Down
| SwarmState::Unknown,
None,
true,
) => {
// Only open unhealthy alert if unhealthy alerts enabled and not in maintenance and buffer is ready
// Only open unreachable alert if not in maintenance and buffer is ready
if !in_maintenance
&& buffer.ready_to_open(
swarm_status.id.clone(),
@@ -116,7 +104,6 @@ pub async fn alert_swarms(
| SwarmState::Down
| SwarmState::Unknown,
Some(alert),
true,
) => {
// update alert err
let mut alert = alert.clone();
@@ -139,23 +126,12 @@ pub async fn alert_swarms(
alerts_to_update.push((alert, false));
}
(
SwarmState::Unhealthy
| SwarmState::Down
| SwarmState::Unknown,
Some(alert),
false,
) => {
alerts_to_close
.push((alert.clone(), swarm.config.send_unhealthy_alerts));
}
// Close an open alert
(SwarmState::Healthy, Some(alert), _) => {
alerts_to_close
(SwarmState::Healthy, Some(alert)) => {
alert_ids_to_close
.push((alert.clone(), swarm.config.send_unhealthy_alerts));
}
(SwarmState::Healthy, None, _) => buffer.reset(
(SwarmState::Healthy, None) => buffer.reset(
swarm_status.id.clone(),
AlertDataVariant::SwarmUnhealthy,
),
@@ -165,7 +141,7 @@ pub async fn alert_swarms(
tokio::join!(
open_new_alerts(&alerts_to_open),
update_alerts(&alerts_to_update),
resolve_alerts(&alerts_to_close),
resolve_alerts(&alert_ids_to_close),
);
}
+168 -180
View File
@@ -41,7 +41,7 @@ mod record;
mod resources;
mod swarm;
pub use swarm::refresh_swarm_cache;
pub use swarm::update_cache_for_swarm;
const ADDITIONAL_MS: u128 = 500;
@@ -52,17 +52,17 @@ pub fn spawn_monitoring_loops() {
fn spawn_server_monitoring_loop() {
tokio::spawn(async move {
refresh_all_server_cache(komodo_timestamp()).await;
refresh_server_cache(komodo_timestamp()).await;
let interval = monitoring_interval();
loop {
let ts = (wait_until_timelength(interval, ADDITIONAL_MS).await
- ADDITIONAL_MS) as i64;
refresh_all_server_cache(ts).await;
refresh_server_cache(ts).await;
}
});
}
async fn refresh_all_server_cache(ts: i64) {
async fn refresh_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_all_server_cache(ts: i64) {
}
};
let futures = servers.into_iter().map(|server| async move {
refresh_server_cache(&server, false).await;
update_cache_for_server(&server, false).await;
});
join_all(futures).await;
tokio::join!(check_alerts(ts), record_server_stats(ts));
@@ -82,7 +82,7 @@ async fn refresh_all_server_cache(ts: i64) {
/// Makes sure cache for server doesn't update too frequently / simultaneously.
/// If forced, will still block against simultaneous update.
fn refresh_server_cache_controller()
fn update_cache_for_server_controller()
-> &'static CloneCache<String, Arc<Mutex<i64>>> {
static CACHE: OnceLock<CloneCache<String, Arc<Mutex<i64>>>> =
OnceLock::new();
@@ -93,176 +93,188 @@ fn refresh_server_cache_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.
///
/// 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,
};
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,
};
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 = 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,
),
);
let resources = UpdateCacheResources::load_server(server).await;
// Handle server disabled
if !server.config.enabled {
resources.insert_status_unknown().await;
insert_server_status(
server,
ServerState::Ok,
Some(periphery_info),
Some(system_info),
system_stats.map(|stats| filter_volumes(server, stats)),
docker,
ServerState::Disabled,
None,
None,
None,
None,
None,
)
.await;
periphery_connections().remove(&server.id).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 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,
),
);
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 RefreshCacheResources {
struct UpdateCacheResources {
stacks: Vec<Stack>,
deployments: Vec<Deployment>,
repos: Vec<Repo>,
}
impl RefreshCacheResources {
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 load_server(server: &Server) -> Self {
let (stacks, deployments, repos) = tokio::join!(
find_collect(
@@ -293,30 +305,6 @@ impl RefreshCacheResources {
}
}
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;
+14 -13
View File
@@ -6,6 +6,7 @@ use std::{
use anyhow::anyhow;
use async_timing_util::wait_until_timelength;
use database::mungos::find::find_collect;
use formatting::format_serror;
use futures_util::future::join_all;
use komodo_client::entities::{
docker::node::NodeState,
@@ -22,7 +23,7 @@ use crate::{
config::monitoring_interval,
helpers::swarm::swarm_request_custom_timeout,
monitor::{
RefreshCacheResources,
UpdateCacheResources,
resources::{
update_swarm_deployment_cache, update_swarm_stack_cache,
},
@@ -34,16 +35,16 @@ const ADDITIONAL_MS: u128 = 1000;
pub fn spawn_swarm_monitoring_loop() {
tokio::spawn(async move {
refresh_all_swarm_cache().await;
refresh_swarm_cache().await;
let interval = monitoring_interval();
loop {
wait_until_timelength(interval, ADDITIONAL_MS).await;
refresh_all_swarm_cache().await;
refresh_swarm_cache().await;
}
});
}
async fn refresh_all_swarm_cache() {
async fn refresh_swarm_cache() {
let swarms =
match find_collect(&db_client().swarms, None, None).await {
Ok(swarms) => swarms,
@@ -55,7 +56,7 @@ async fn refresh_all_swarm_cache() {
}
};
let futures = swarms.into_iter().map(|swarm| async move {
refresh_swarm_cache(&swarm, false).await;
update_cache_for_swarm(&swarm, false).await;
});
join_all(futures).await;
// tokio::join!(check_alerts(ts), record_swarm_stats(ts));
@@ -63,7 +64,7 @@ async fn refresh_all_swarm_cache() {
/// Makes sure cache for swarm doesn't update too frequently / simultaneously.
/// If forced, will still block against simultaneous update.
fn refresh_swarm_cache_controller()
fn update_cache_for_swarm_controller()
-> &'static CloneCache<String, Arc<Mutex<i64>>> {
static CACHE: OnceLock<CloneCache<String, Arc<Mutex<i64>>>> =
OnceLock::new();
@@ -74,10 +75,10 @@ fn refresh_swarm_cache_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 refresh_swarm_cache(swarm: &Swarm, force: bool) {
pub async fn update_cache_for_swarm(swarm: &Swarm, force: bool) {
// Concurrency controller to ensure it isn't done too often
// when it happens in other contexts.
let controller = refresh_swarm_cache_controller()
let controller = update_cache_for_swarm_controller()
.get_or_insert_default(&swarm.id)
.await;
let mut lock = match controller.try_lock() {
@@ -95,7 +96,7 @@ pub async fn refresh_swarm_cache(swarm: &Swarm, force: bool) {
*lock = now;
let resources = RefreshCacheResources::load_swarm(swarm).await;
let resources = UpdateCacheResources::load_swarm(swarm).await;
if swarm.config.server_ids.is_empty() {
resources.insert_status_unknown().await;
@@ -107,9 +108,9 @@ pub async fn refresh_swarm_cache(swarm: &Swarm, force: bool) {
state: SwarmState::Unknown,
inspect: None,
lists: None,
err: Some(
anyhow!("No servers configured as manager nodes").into(),
),
err: Some(format_serror(
&anyhow!("No Servers configured as manager nodes").into(),
)),
}
.into(),
)
@@ -136,7 +137,7 @@ pub async fn refresh_swarm_cache(swarm: &Swarm, force: bool) {
state: SwarmState::Unknown,
inspect: None,
lists: None,
err: Some(e.into()),
err: Some(format_serror(&e.into())),
}
.into(),
)
+4 -10
View File
@@ -33,7 +33,7 @@ use crate::{
query::{get_deployment_state, get_swarm_or_server},
swarm::swarm_request,
},
monitor::{refresh_server_cache, refresh_swarm_cache},
monitor::{update_cache_for_server, update_cache_for_swarm},
state::{action_states, db_client, deployment_status_cache},
};
@@ -72,13 +72,7 @@ impl super::KomodoResource for Deployment {
fn inherit_specific_permissions_from(
_self: &Resource<Self::Config, Self::Info>,
) -> Option<ResourceTarget> {
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
}
ResourceTarget::Server(_self.config.server_id.clone()).into()
}
fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
@@ -227,10 +221,10 @@ impl super::KomodoResource for Deployment {
};
match swarm_or_server {
SwarmOrServer::Swarm(swarm) => {
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
SwarmOrServer::Server(server) => {
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
}
SwarmOrServer::None => {}
}
+684 -172
View File
@@ -183,183 +183,695 @@ async fn validate_config(
};
for stage in stages {
for exec in &mut stage.executions {
macro_rules! check_execution_perms {
(
execute: [$(($Variant:ident, $Type:ident, $field:ident)),* $(,)?],
batch_admin: [$($BatchVariant:ident),* $(,)?],
admin_only: [$(($AdminVariant:ident, $msg:literal)),* $(,)?],
) => {
match &mut exec.execution {
$(
Execution::$Variant(params) => {
let resource = super::get_check_permissions::<$Type>(
&params.$field,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.$field = resource.id;
}
)*
$(
Execution::$BatchVariant(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
)*
$(
Execution::$AdminVariant(_params) => {
if !user.admin {
return Err(anyhow!($msg));
}
}
)*
// Special: self-referential procedure check
Execution::RunProcedure(params) => {
let procedure = super::get_check_permissions::<Procedure>(
&params.procedure,
match &mut exec.execution {
Execution::None(_) => {}
Execution::RunProcedure(params) => {
let procedure = super::get_check_permissions::<Procedure>(
&params.procedure,
user,
PermissionLevel::Execute.into(),
)
.await?;
match id {
Some(id) if procedure.id == id => {
return Err(anyhow!(
"Cannot have self-referential procedure"
));
}
_ => {}
}
params.procedure = procedure.id;
}
Execution::BatchRunProcedure(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::RunAction(params) => {
let action = super::get_check_permissions::<Action>(
&params.action,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.action = action.id;
}
Execution::BatchRunAction(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::RunBuild(params) => {
let build = super::get_check_permissions::<Build>(
&params.build,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.build = build.id;
}
Execution::BatchRunBuild(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::CancelBuild(params) => {
let build = super::get_check_permissions::<Build>(
&params.build,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.build = build.id;
}
Execution::Deploy(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::BatchDeploy(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::PullDeployment(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::StartDeployment(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::RestartDeployment(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::PauseDeployment(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::UnpauseDeployment(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::StopDeployment(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::DestroyDeployment(params) => {
let deployment =
super::get_check_permissions::<Deployment>(
&params.deployment,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.deployment = deployment.id;
}
Execution::BatchDestroyDeployment(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::CloneRepo(params) => {
let repo = super::get_check_permissions::<Repo>(
&params.repo,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.repo = repo.id;
}
Execution::BatchCloneRepo(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::PullRepo(params) => {
let repo = super::get_check_permissions::<Repo>(
&params.repo,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.repo = repo.id;
}
Execution::BatchPullRepo(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::BuildRepo(params) => {
let repo = super::get_check_permissions::<Repo>(
&params.repo,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.repo = repo.id;
}
Execution::BatchBuildRepo(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::CancelRepoBuild(params) => {
let repo = super::get_check_permissions::<Repo>(
&params.repo,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.repo = repo.id;
}
Execution::StartContainer(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::RestartContainer(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PauseContainer(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::UnpauseContainer(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::StopContainer(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::DestroyContainer(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::StartAllContainers(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::RestartAllContainers(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PauseAllContainers(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::UnpauseAllContainers(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::StopAllContainers(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PruneContainers(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::DeleteNetwork(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PruneNetworks(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::DeleteImage(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PruneImages(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::DeleteVolume(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PruneVolumes(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PruneDockerBuilders(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PruneBuildx(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::PruneSystem(params) => {
let server = super::get_check_permissions::<Server>(
&params.server,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.server = server.id;
}
Execution::RunSync(params) => {
let sync = super::get_check_permissions::<ResourceSync>(
&params.sync,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.sync = sync.id;
}
Execution::CommitSync(params) => {
// This one is actually a write operation.
let sync = super::get_check_permissions::<ResourceSync>(
&params.sync,
user,
PermissionLevel::Write.into(),
)
.await?;
params.sync = sync.id;
}
Execution::DeployStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::BatchDeployStack(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::DeployStackIfChanged(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::BatchDeployStackIfChanged(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::PullStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::BatchPullStack(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::StartStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::RestartStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::PauseStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::UnpauseStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::StopStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::DestroyStack(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::RunStackService(params) => {
let stack = super::get_check_permissions::<Stack>(
&params.stack,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.stack = stack.id;
}
Execution::BatchDestroyStack(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot configure Batch executions"
));
}
}
Execution::TestAlerter(params) => {
let alerter = super::get_check_permissions::<Alerter>(
&params.alerter,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.alerter = alerter.id;
}
Execution::SendAlert(params) => {
params.alerters = params
.alerters
.iter()
.map(async |alerter| {
let id = super::get_check_permissions::<Alerter>(
alerter,
user,
PermissionLevel::Execute.into(),
)
.await?;
match id {
Some(id) if procedure.id == id => {
return Err(anyhow!(
"Cannot have self-referential procedure"
));
}
_ => {}
}
params.procedure = procedure.id;
}
// Special: CommitSync uses Write permission
Execution::CommitSync(params) => {
let sync = super::get_check_permissions::<ResourceSync>(
&params.sync,
user,
PermissionLevel::Write.into(),
)
.await?;
params.sync = sync.id;
}
// Special: SendAlert checks a Vec of alerters
Execution::SendAlert(params) => {
params.alerters = params
.alerters
.iter()
.map(async |alerter| {
let id = super::get_check_permissions::<Alerter>(
alerter,
user,
PermissionLevel::Execute.into(),
)
.await?
.id;
anyhow::Ok(id)
})
.collect::<FuturesUnordered<_>>()
.try_collect::<Vec<_>>()
.await?;
}
Execution::None(_) | Execution::Sleep(_) => {}
.await?
.id;
anyhow::Ok(id)
})
.collect::<FuturesUnordered<_>>()
.try_collect::<Vec<_>>()
.await?;
}
Execution::RemoveSwarmNodes(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::RemoveSwarmStacks(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::RemoveSwarmServices(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::CreateSwarmConfig(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::RotateSwarmConfig(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::RemoveSwarmConfigs(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::CreateSwarmSecret(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::RotateSwarmSecret(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::RemoveSwarmSecrets(params) => {
let swarm = super::get_check_permissions::<Swarm>(
&params.swarm,
user,
PermissionLevel::Execute.into(),
)
.await?;
params.swarm = swarm.id;
}
Execution::ClearRepoCache(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot clear repo cache"
));
}
};
}
Execution::BackupCoreDatabase(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot trigger core database backup"
));
}
}
Execution::GlobalAutoUpdate(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot trigger global auto update"
));
}
}
Execution::RotateAllServerKeys(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot trigger rotate all server keys"
));
}
}
Execution::RotateCoreKeys(_params) => {
if !user.admin {
return Err(anyhow!(
"Non admin user cannot trigger rotate core keys"
));
}
}
Execution::Sleep(_) => {}
}
check_execution_perms!(
execute: [
// Action
(RunAction, Action, action),
// Build
(RunBuild, Build, build),
(CancelBuild, Build, build),
// Deployment
(Deploy, Deployment, deployment),
(PullDeployment, Deployment, deployment),
(StartDeployment, Deployment, deployment),
(RestartDeployment, Deployment, deployment),
(PauseDeployment, Deployment, deployment),
(UnpauseDeployment, Deployment, deployment),
(StopDeployment, Deployment, deployment),
(DestroyDeployment, Deployment, deployment),
// Repo
(CloneRepo, Repo, repo),
(PullRepo, Repo, repo),
(BuildRepo, Repo, repo),
(CancelRepoBuild, Repo, repo),
// Server
(StartContainer, Server, server),
(RestartContainer, Server, server),
(PauseContainer, Server, server),
(UnpauseContainer, Server, server),
(StopContainer, Server, server),
(DestroyContainer, Server, server),
(StartAllContainers, Server, server),
(RestartAllContainers, Server, server),
(PauseAllContainers, Server, server),
(UnpauseAllContainers, Server, server),
(StopAllContainers, Server, server),
(PruneContainers, Server, server),
(DeleteNetwork, Server, server),
(PruneNetworks, Server, server),
(DeleteImage, Server, server),
(PruneImages, Server, server),
(DeleteVolume, Server, server),
(PruneVolumes, Server, server),
(PruneDockerBuilders, Server, server),
(PruneBuildx, Server, server),
(PruneSystem, Server, server),
// Resource Sync
(RunSync, ResourceSync, sync),
// Stack
(DeployStack, Stack, stack),
(DeployStackIfChanged, Stack, stack),
(PullStack, Stack, stack),
(StartStack, Stack, stack),
(RestartStack, Stack, stack),
(PauseStack, Stack, stack),
(UnpauseStack, Stack, stack),
(StopStack, Stack, stack),
(DestroyStack, Stack, stack),
(RunStackService, Stack, stack),
// Alerter
(TestAlerter, Alerter, alerter),
// Swarm
(RemoveSwarmNodes, Swarm, swarm),
(UpdateSwarmNode, Swarm, swarm),
(RemoveSwarmStacks, Swarm, swarm),
(RemoveSwarmServices, Swarm, swarm),
(CreateSwarmConfig, Swarm, swarm),
(RotateSwarmConfig, Swarm, swarm),
(RemoveSwarmConfigs, Swarm, swarm),
(CreateSwarmSecret, Swarm, swarm),
(RotateSwarmSecret, Swarm, swarm),
(RemoveSwarmSecrets, Swarm, swarm),
],
batch_admin: [
BatchRunProcedure,
BatchRunAction,
BatchRunBuild,
BatchDeploy,
BatchDestroyDeployment,
BatchCloneRepo,
BatchPullRepo,
BatchBuildRepo,
BatchDeployStack,
BatchDeployStackIfChanged,
BatchPullStack,
BatchDestroyStack,
],
admin_only: [
(ClearRepoCache, "Non admin user cannot clear repo cache"),
(BackupCoreDatabase, "Non admin user cannot trigger core database backup"),
(GlobalAutoUpdate, "Non admin user cannot trigger global auto update"),
(RotateAllServerKeys, "Non admin user cannot trigger rotate all server keys"),
(RotateCoreKeys, "Non admin user cannot trigger rotate core keys"),
],
);
}
}
+3 -4
View File
@@ -24,7 +24,7 @@ use periphery_client::api;
use crate::{
config::core_config,
helpers::periphery_client,
monitor::refresh_server_cache,
monitor::update_cache_for_server,
state::{
action_states, db_client, periphery_connections,
server_status_cache,
@@ -93,7 +93,6 @@ impl super::KomodoResource for Server {
resource_type: ResourceTargetVariant::Server,
info: ServerListItemInfo {
state: status.as_ref().map(|s| s.state).unwrap_or_default(),
err: status.as_ref().and_then(|s| s.err.clone()),
region: server.config.region,
address: optional_string(server.config.address),
external_address: optional_string(
@@ -152,7 +151,7 @@ impl super::KomodoResource for Server {
created: &Resource<Self::Config, Self::Info>,
_update: &mut Update,
) -> anyhow::Result<()> {
refresh_server_cache(created, true).await;
update_cache_for_server(created, true).await;
Ok(())
}
@@ -174,7 +173,7 @@ impl super::KomodoResource for Server {
updated: &Self,
_update: &mut Update,
) -> anyhow::Result<()> {
refresh_server_cache(updated, true).await;
update_cache_for_server(updated, true).await;
Ok(())
}
+4 -10
View File
@@ -35,7 +35,7 @@ use crate::{
repo_link,
swarm::swarm_request,
},
monitor::{refresh_server_cache, refresh_swarm_cache},
monitor::{update_cache_for_server, update_cache_for_swarm},
state::{
action_states, all_resources_cache, db_client,
server_status_cache, stack_status_cache,
@@ -77,13 +77,7 @@ impl super::KomodoResource for Stack {
fn inherit_specific_permissions_from(
_self: &Resource<Self::Config, Self::Info>,
) -> Option<ResourceTarget> {
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
}
ResourceTarget::Server(_self.config.server_id.clone()).into()
}
fn coll() -> &'static Collection<Resource<Self::Config, Self::Info>>
@@ -300,10 +294,10 @@ impl super::KomodoResource for Stack {
};
match swarm_or_server {
SwarmOrServer::Swarm(swarm) => {
refresh_swarm_cache(&swarm, true).await;
update_cache_for_swarm(&swarm, true).await;
}
SwarmOrServer::Server(server) => {
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
}
SwarmOrServer::None => {}
}
+3 -3
View File
@@ -15,7 +15,7 @@ use komodo_client::entities::{
use crate::{
config::core_config,
monitor::refresh_swarm_cache,
monitor::update_cache_for_swarm,
state::{db_client, swarm_status_cache},
};
@@ -89,7 +89,7 @@ impl super::KomodoResource for Swarm {
created: &Self,
_update: &mut Update,
) -> anyhow::Result<()> {
refresh_swarm_cache(created, true).await;
update_cache_for_swarm(created, true).await;
Ok(())
}
@@ -111,7 +111,7 @@ impl super::KomodoResource for Swarm {
updated: &Self,
_update: &mut Update,
) -> anyhow::Result<()> {
refresh_swarm_cache(updated, true).await;
update_cache_for_swarm(updated, true).await;
Ok(())
}
+8 -6
View File
@@ -10,7 +10,12 @@ use komodo_client::{
permission::PermissionLevel,
repo::Repo,
resource::Resource,
sync::*,
sync::{
PartialResourceSyncConfig, ResourceSync, ResourceSyncConfig,
ResourceSyncConfigDiff, ResourceSyncInfo, ResourceSyncListItem,
ResourceSyncListItemInfo, ResourceSyncQuerySpecifics,
ResourceSyncState,
},
update::Update,
user::{User, sync_user},
},
@@ -255,15 +260,12 @@ async fn get_resource_sync_state(
{
return state;
}
if data.pending_error.is_some()
|| data.pending_deploy_error.is_some()
|| !data.remote_errors.is_empty()
{
if data.pending_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_deploys.is_empty()
|| data.pending_deploy.to_deploy > 0
{
ResourceSyncState::Pending
} else {
+2 -2
View File
@@ -109,7 +109,7 @@ pub fn spawn_schedule_executor() {
.resolve(&ExecuteArgs {
user: action_user().to_owned(),
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
{
@@ -180,7 +180,7 @@ pub fn spawn_schedule_executor() {
.resolve(&ExecuteArgs {
user: procedure_user().to_owned(),
update,
task_id: Uuid::new_v4(),
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::refresh_server_cache,
monitor::update_cache_for_server,
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
refresh_server_cache(&server, true).await;
update_cache_for_server(&server, true).await;
update.finalize();
update_update(update.clone()).await?;
+20 -20
View File
@@ -1,6 +1,7 @@
use std::str::FromStr;
use anyhow::Context;
use colored::Colorize;
use database::mungos::{
find::find_collect,
mongodb::bson::{
@@ -32,7 +33,6 @@ 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,7 +41,6 @@ use crate::{
execute::{ExecuteArgs, ExecuteRequest},
write::WriteArgs,
},
auth::KomodoAuthImpl,
config::core_config,
helpers::update::init_execution_update,
network, resource,
@@ -92,7 +91,7 @@ pub async fn run_startup_actions() {
.resolve(&ExecuteArgs {
user: action_user().to_owned(),
update,
task_id: Uuid::new_v4(),
id: Uuid::new_v4(),
})
.await
{
@@ -302,7 +301,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, procedures, tags)) = tokio::try_join!(
let Ok((None, None, None)) = tokio::try_join!(
db.users.find_one(Document::new()),
db.procedures.find_one(Document::new()),
db.tags.find_one(Document::new()),
@@ -315,16 +314,20 @@ 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) = sign_up_local_user(
&KomodoAuthImpl,
username.to_string(),
&config.init_admin_password,
)
.await
{
error!("Failed to create init admin user | {:#}", e.error);
return;
}
// 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;
// }
match db
.users
.find_one(doc! { "username": username })
@@ -344,15 +347,12 @@ async fn ensure_init_user_and_resources() {
}
}
if config.disable_init_resources
|| procedures.is_some()
|| tags.is_some()
{
info!("Skipping initial system resource creation");
if config.disable_init_resources {
info!("System resources init {}", "DISABLED".red());
return;
}
info!("Creating initial system resources...");
info!("Creating init system resources...");
let write_args = WriteArgs {
user: system_user().to_owned(),
+2 -2
View File
@@ -87,7 +87,7 @@ pub struct CachedSwarmStatus {
pub inspect: Option<SwarmInspectInfo>,
pub lists: Option<SwarmLists>,
/// Store the error in communicating with Swarm
pub err: Option<mogh_error::Serror>,
pub err: Option<String>,
}
pub type SwarmStatusCache =
@@ -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())
}
+54 -27
View File
@@ -18,7 +18,7 @@ use komodo_client::{
PartialStackConfig, Stack, StackConfig,
StackRemoteFileContents, StackState,
},
sync::SyncDeployTarget,
sync::SyncDeployUpdate,
toml::ResourceToml,
update::Log,
user::sync_user,
@@ -41,7 +41,8 @@ use super::ResourceSyncTrait;
/// All entries in here are due to be deployed,
/// after the given dependencies,
/// with the given reason.
pub type ToDeployCache = Vec<SyncDeployTarget>;
pub type ToDeployCache =
Vec<(ResourceTarget, String, Vec<ResourceTarget>)>;
#[derive(Clone, Copy)]
pub struct SyncDeployParams<'a> {
@@ -71,16 +72,14 @@ pub async fn deploy_from_cache(
// Collect all waiting deployments without waiting dependencies.
let good_to_deploy = to_deploy
.iter()
.filter(|SyncDeployTarget { after, .. }| {
to_deploy.iter().all(|SyncDeployTarget { target, .. }| {
!after.contains(target)
})
.filter(|(_, _, after)| {
to_deploy
.iter()
.all(|(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(|SyncDeployTarget { target, reason, .. }| {
(target.clone(), reason.clone())
})
.map(|(target, reason, _)| (target.clone(), reason.clone()))
.collect::<HashMap<_, _>>();
// Deploy the ones ready for deployment
@@ -104,7 +103,7 @@ pub async fn deploy_from_cache(
.resolve(&ExecuteArgs {
user: user.to_owned(),
update,
task_id: id,
id,
})
.await
}
@@ -123,7 +122,7 @@ pub async fn deploy_from_cache(
.resolve(&ExecuteArgs {
user: user.to_owned(),
update,
task_id: id,
id,
})
.await
}
@@ -173,9 +172,8 @@ pub async fn deploy_from_cache(
}
// Remove the deployed ones from 'to_deploy'
to_deploy.retain(|SyncDeployTarget { target, .. }| {
!good_to_deploy.contains_key(target)
});
to_deploy
.retain(|(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
@@ -198,10 +196,46 @@ pub async fn deploy_from_cache(
pub async fn get_updates_for_view(
params: SyncDeployParams<'_>,
) -> (Vec<SyncDeployTarget>, Option<String>) {
match build_deploy_cache(params).await {
Ok(targets) => (targets, None),
Err(e) => (Vec::new(), Some(format_serror(&e.into()))),
) -> 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(),
),
},
}
}
@@ -260,11 +294,7 @@ pub async fn build_deploy_cache(
.map(|(target, (reason, mut after))| {
// Only keep targets which are deploying.
after.retain(|target| clone.contains_key(target));
SyncDeployTarget {
target,
reason,
after,
}
(target, reason, after)
})
.collect(),
)
@@ -590,12 +620,9 @@ 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.compose_cmd_wrapper.is_some();
|| diff.commit.is_some();
if changed {
cache.insert(
target,
+30 -21
View File
@@ -243,27 +243,36 @@ pub fn extend_resources(
more: ResourcesToml,
match_tags: &[String],
) {
macro_rules! extend_filtered {
($($field:ident),* $(,)?) => {
$(
resources.$field.extend(filter_by_tag(more.$field, match_tags));
)*
};
}
// New resource types need to be added here manually.
extend_filtered!(
servers,
swarms,
stacks,
deployments,
builds,
repos,
procedures,
actions,
alerters,
builders,
resource_syncs,
);
resources
.servers
.extend(filter_by_tag(more.servers, match_tags));
resources
.stacks
.extend(filter_by_tag(more.stacks, match_tags));
resources
.deployments
.extend(filter_by_tag(more.deployments, match_tags));
resources
.builds
.extend(filter_by_tag(more.builds, match_tags));
resources
.repos
.extend(filter_by_tag(more.repos, match_tags));
resources
.procedures
.extend(filter_by_tag(more.procedures, match_tags));
resources
.actions
.extend(filter_by_tag(more.actions, match_tags));
resources
.alerters
.extend(filter_by_tag(more.alerters, match_tags));
resources
.builders
.extend(filter_by_tag(more.builders, match_tags));
resources
.resource_syncs
.extend(filter_by_tag(more.resource_syncs, match_tags));
resources.user_groups.extend(more.user_groups);
resources.variables.extend(more.variables);
}
+500 -57
View File
@@ -1,27 +1,29 @@
use std::collections::HashMap;
use formatting::{Color, bold, colored, muted};
use komodo_client::entities::{
ResourceTargetVariant,
action::Action,
alerter::Alerter,
build::Build,
builder::{Builder, BuilderConfig},
deployment::{Deployment, DeploymentImage},
procedure::Procedure,
repo::Repo,
server::Server,
stack::Stack,
swarm::Swarm,
sync::ResourceSync,
tag::Tag,
update::Log,
user::sync_user,
use komodo_client::{
api::execute::Execution,
entities::{
ResourceTargetVariant,
action::Action,
alerter::Alerter,
build::Build,
builder::{Builder, BuilderConfig},
deployment::{Deployment, DeploymentImage},
procedure::Procedure,
repo::Repo,
server::Server,
stack::Stack,
swarm::Swarm,
sync::ResourceSync,
tag::Tag,
update::Log,
user::sync_user,
},
};
use partial_derive2::{MaybeNone, PartialDiff};
use crate::{
helpers::procedure::replace_procedure_stage_ids_with_names,
resource::{KomodoResource, ResourceMetaUpdate},
state::all_resources_cache,
sync::{ToUpdateItem, execute::run_update_meta},
@@ -33,6 +35,17 @@ 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,
@@ -44,41 +57,20 @@ 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 all = all_resources_cache().load();
let resources = all_resources_cache().load();
original.swarm_id = all
original.swarm_id = resources
.swarms
.get(&original.swarm_id)
.map(|s| s.name.clone())
.unwrap_or_default();
original.server_id = all
original.server_id = resources
.servers
.get(&original.server_id)
.map(|s| s.name.clone())
@@ -88,7 +80,7 @@ impl ResourceSyncTrait for Deployment {
&original.image
{
original.image = DeploymentImage::Build {
build_id: all
build_id: resources
.builds
.get(build_id)
.map(|b| b.name.clone())
@@ -108,21 +100,21 @@ impl ResourceSyncTrait for Stack {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let all = all_resources_cache().load();
let resources = all_resources_cache().load();
original.swarm_id = all
original.swarm_id = resources
.swarms
.get(&original.swarm_id)
.map(|s| s.name.clone())
.unwrap_or_default();
original.server_id = all
original.server_id = resources
.servers
.get(&original.server_id)
.map(|s| s.name.clone())
.unwrap_or_default();
original.linked_repo = all
original.linked_repo = resources
.repos
.get(&original.linked_repo)
.map(|r| r.name.clone())
@@ -139,13 +131,13 @@ impl ResourceSyncTrait for Build {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let all = all_resources_cache().load();
original.builder_id = all
let resources = all_resources_cache().load();
original.builder_id = resources
.builders
.get(&original.builder_id)
.map(|b| b.name.clone())
.unwrap_or_default();
original.linked_repo = all
original.linked_repo = resources
.repos
.get(&original.linked_repo)
.map(|r| r.name.clone())
@@ -173,16 +165,16 @@ impl ResourceSyncTrait for Repo {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let all = all_resources_cache().load();
let resources = all_resources_cache().load();
// Need to replace server id with name
original.server_id = all
original.server_id = resources
.servers
.get(&original.server_id)
.map(|s| s.name.clone())
.unwrap_or_default();
// Need to replace builder id with name
original.builder_id = all
original.builder_id = resources
.builders
.get(&original.builder_id)
.map(|s| s.name.clone())
@@ -212,8 +204,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 all = all_resources_cache().load();
config.server_id = all
let resources = all_resources_cache().load();
config.server_id = resources
.servers
.get(&config.server_id)
.map(|s| s.name.clone())
@@ -321,8 +313,8 @@ impl ResourceSyncTrait for ResourceSync {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
let all = all_resources_cache().load();
original.linked_repo = all
let resources = all_resources_cache().load();
original.linked_repo = resources
.repos
.get(&original.linked_repo)
.map(|r| r.name.clone())
@@ -339,7 +331,458 @@ impl ResourceSyncTrait for Procedure {
mut original: Self::Config,
update: Self::PartialConfig,
) -> anyhow::Result<Self::ConfigDiff> {
replace_procedure_stage_ids_with_names(&mut original.stages);
let resources = 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
.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(_) => {}
}
}
}
Ok(original.partial_diff(update))
}
}
+519 -30
View File
@@ -2,28 +2,28 @@ use std::collections::HashMap;
use anyhow::Context;
use indexmap::IndexMap;
use komodo_client::entities::{
action::Action,
alerter::Alerter,
build::Build,
builder::{Builder, BuilderConfig, PartialBuilderConfig},
deployment::{Deployment, DeploymentImage},
procedure::Procedure,
repo::Repo,
resource::Resource,
server::Server,
stack::Stack,
swarm::Swarm,
sync::ResourceSync,
tag::Tag,
toml::ResourceToml,
use komodo_client::{
api::execute::Execution,
entities::{
action::Action,
alerter::Alerter,
build::Build,
builder::{Builder, BuilderConfig, PartialBuilderConfig},
deployment::{Deployment, DeploymentImage},
procedure::Procedure,
repo::Repo,
resource::Resource,
server::Server,
stack::Stack,
swarm::Swarm,
sync::ResourceSync,
tag::Tag,
toml::ResourceToml,
},
};
use partial_derive2::{MaybeNone, PartialDiff};
use crate::{
helpers::procedure::replace_procedure_stage_ids_with_names,
resource::KomodoResource, state::all_resources_cache,
};
use crate::{resource::KomodoResource, state::all_resources_cache};
pub const TOML_PRETTY_OPTIONS: toml_pretty::Options =
toml_pretty::Options {
@@ -178,14 +178,6 @@ 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 {
@@ -462,9 +454,506 @@ impl ToToml for Builder {
impl ToToml for Procedure {
fn replace_ids(resource: &mut Resource<Self::Config, Self::Info>) {
replace_procedure_stage_ids_with_names(
&mut resource.config.stages,
);
let all = all_resources_cache().load();
for stage in &mut resource.config.stages {
for execution in &mut stage.executions {
match &mut execution.execution {
Execution::RunProcedure(exec) => exec.procedure.clone_from(
all
.procedures
.get(&exec.procedure)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchRunProcedure(_exec) => {}
Execution::RunAction(exec) => exec.action.clone_from(
all
.actions
.get(&exec.action)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchRunAction(_exec) => {}
Execution::RunBuild(exec) => exec.build.clone_from(
all
.builds
.get(&exec.build)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchRunBuild(_exec) => {}
Execution::CancelBuild(exec) => exec.build.clone_from(
all
.builds
.get(&exec.build)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::Deploy(exec) => exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchDeploy(_exec) => {}
Execution::PullDeployment(exec) => {
exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::StartDeployment(exec) => {
exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::RestartDeployment(exec) => {
exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::PauseDeployment(exec) => {
exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::UnpauseDeployment(exec) => {
exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::StopDeployment(exec) => {
exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::DestroyDeployment(exec) => {
exec.deployment.clone_from(
all
.deployments
.get(&exec.deployment)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::BatchDestroyDeployment(_exec) => {}
Execution::CloneRepo(exec) => exec.repo.clone_from(
all
.repos
.get(&exec.repo)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchCloneRepo(_exec) => {}
Execution::PullRepo(exec) => exec.repo.clone_from(
all
.repos
.get(&exec.repo)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchPullRepo(_exec) => {}
Execution::BuildRepo(exec) => exec.repo.clone_from(
all
.repos
.get(&exec.repo)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchBuildRepo(_exec) => {}
Execution::CancelRepoBuild(exec) => exec.repo.clone_from(
all
.repos
.get(&exec.repo)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::StartContainer(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::RestartContainer(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::PauseContainer(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::UnpauseContainer(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::StopContainer(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::DestroyContainer(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::StartAllContainers(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::RestartAllContainers(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::PauseAllContainers(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::UnpauseAllContainers(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::StopAllContainers(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::PruneContainers(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::DeleteNetwork(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::PruneNetworks(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::DeleteImage(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::PruneImages(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::DeleteVolume(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::PruneVolumes(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::PruneDockerBuilders(exec) => {
exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::PruneBuildx(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::PruneSystem(exec) => exec.server.clone_from(
all
.servers
.get(&exec.server)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::RunSync(exec) => exec.sync.clone_from(
all
.syncs
.get(&exec.sync)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::CommitSync(exec) => exec.sync.clone_from(
all
.syncs
.get(&exec.sync)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::DeployStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchDeployStack(_exec) => {}
Execution::DeployStackIfChanged(exec) => {
exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
)
}
Execution::BatchDeployStackIfChanged(_exec) => {}
Execution::PullStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchPullStack(_exec) => {}
Execution::StartStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::RestartStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::RunStackService(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::PauseStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::UnpauseStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::StopStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::DestroyStack(exec) => exec.stack.clone_from(
all
.stacks
.get(&exec.stack)
.map(|r| &r.name)
.unwrap_or(&String::new()),
),
Execution::BatchDestroyStack(_exec) => {}
Execution::TestAlerter(exec) => exec.alerter.clone_from(
all
.alerters
.get(&exec.alerter)
.map(|a| &a.name)
.unwrap_or(&String::new()),
),
Execution::SendAlert(exec) => {
exec.alerters.iter_mut().for_each(|a| {
a.clone_from(
all
.alerters
.get(a)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
})
}
Execution::RemoveSwarmNodes(exec) => exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
),
Execution::RemoveSwarmStacks(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::RemoveSwarmServices(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::CreateSwarmConfig(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::RotateSwarmConfig(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::RemoveSwarmConfigs(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::CreateSwarmSecret(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::RotateSwarmSecret(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::RemoveSwarmSecrets(exec) => {
exec.swarm.clone_from(
all
.swarms
.get(&exec.swarm)
.map(|a| &a.name)
.unwrap_or(&String::new()),
)
}
Execution::None(_)
| Execution::Sleep(_)
| Execution::ClearRepoCache(_)
| Execution::BackupCoreDatabase(_)
| Execution::GlobalAutoUpdate(_)
| Execution::RotateAllServerKeys(_)
| Execution::RotateCoreKeys(_) => {}
}
}
}
}
fn push_to_toml_string(
+1 -1
View File
@@ -1,6 +1,6 @@
## All in one, multi stage compile + runtime Docker build for your architecture.
FROM rust:1.94.1-trixie AS builder
FROM rust:1.93.1-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:2
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
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:2
ARG BINARIES_IMAGE=ghcr.io/moghtech/komodo-binaries:latest
# This is required to work with COPY --from
FROM ${BINARIES_IMAGE} AS binaries
+42 -217
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().with_context(||
format!("Failed to validate run directory on host after stack write (canonicalize error), path={}", run_directory.to_string_lossy()),
let run_directory = run_directory.canonicalize().context(
"Failed to validate run directory on host after stack write (canonicalize error)",
)?;
let file_paths = stack
@@ -352,56 +352,16 @@ 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 mode = if wrapped {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let Some(log) = run_komodo_command_with_sanitization(
let log = run_komodo_standard_command(
"Compose Pull",
run_directory.as_path(),
pull_command,
mode,
&replacers,
run_directory.as_ref(),
format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} pull{service_args}",
),
)
.instrument(span)
.await
else {
// Only reachable if command is empty,
// not the case since it is provided above.
unreachable!()
};
.await;
res.logs.push(log);
@@ -467,8 +427,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().with_context(||
format!("Failed to validate run directory on host after stack write (canonicalize error), path={}", run_directory.to_string_lossy()),
let run_directory = run_directory.canonicalize().context(
"Failed to validate run directory on host after stack write (canonicalize error)",
)?;
validate_files(&stack, &run_directory, &mut res).await;
@@ -523,54 +483,25 @@ 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,
mode,
KomodoCommandMode::Standard,
&replacers,
)
.instrument(span)
.await
else {
// Only reachable if command is empty,
// not the case since it is provided above.
unreachable!()
};
if !config_log.success {
@@ -627,29 +558,12 @@ 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,
mode,
KomodoCommandMode::Shell,
&replacers,
)
.instrument(span)
@@ -670,36 +584,14 @@ 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 (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(
let log = run_komodo_standard_command(
"Compose Pull",
run_directory.as_path(),
run_directory.as_ref(),
command,
mode,
&replacers,
)
.instrument(span)
.await
else {
unreachable!()
};
.await;
res.logs.push(log);
if !all_logs_success(&res.logs) {
return Ok(res);
@@ -719,21 +611,24 @@ impl Resolve<crate::api::Args> for ComposeUp {
// Run compose up
let extra_args = format_extra_args(&stack.config.extra_args);
let command = format!(
let mut command = format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} up -d{extra_args}{service_args}",
);
let (command, _) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"up",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
// 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(),
));
return Ok(res);
}
};
command =
compose_cmd_wrapper.replace("[[COMPOSE_COMMAND]]", &command);
}
let span = info_span!("ExecuteComposeUp");
let Some(log) = run_komodo_command_with_sanitization(
@@ -867,8 +762,8 @@ impl Resolve<crate::api::Args> for ComposeRun {
}
};
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 run_directory = run_directory.canonicalize().context(
"Failed to validate run directory on host after stack write (canonicalize error)",
)?;
maybe_login_registry(&stack, registry_token, &mut Vec::new())
@@ -889,49 +784,15 @@ 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_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(
let pull_log = run_komodo_standard_command(
"Compose Pull",
run_directory.as_path(),
pull_command,
mode,
&replacers,
run_directory.as_ref(),
format!(
"{docker_compose} -p {project_name} -f {file_args}{env_file_args} pull {service}",
),
)
.await
else {
unreachable!()
};
.await;
if !pull_log.success {
return Ok(pull_log);
}
@@ -978,24 +839,15 @@ impl Resolve<crate::api::Args> for ComposeRun {
})
.unwrap_or_default();
let run_command = format!(
let 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", run_command);
let span = info_span!("RunComposeRun", command);
let Some(log) = run_komodo_command_with_sanitization(
"Compose Run",
run_directory.as_path(),
run_command,
command,
KomodoCommandMode::Shell,
&replacers,
)
@@ -1036,33 +888,6 @@ 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,
+6 -2
View File
@@ -99,9 +99,13 @@ impl Resolve<crate::api::Args> for UpdateSwarmNode {
}
if let Some(label_add) = self.label_add {
for key_value in label_add {
for (key, value) in label_add {
command += " --label-add ";
command += &key_value;
command += &key;
if let Some(value) = value {
command += "=";
command += &value;
}
}
}
+17 -120
View File
@@ -11,10 +11,7 @@ use komodo_client::{
entities::{
all_logs_success,
docker::stack::SwarmStack,
stack::{
AdditionalEnvFile, ComposeFile, ComposeService,
StackServiceNames,
},
stack::{ComposeFile, ComposeService, StackServiceNames},
update::Log,
},
parsers::parse_multiline_command,
@@ -33,32 +30,6 @@ 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,
@@ -142,7 +113,7 @@ impl Resolve<crate::api::Args> for DeploySwarmStack {
replacers.extend(interpolator.secret_replacers);
// Env files are not supported by docker stack deploy so are ignored.
let (run_directory, env_file_path) = match write_stack(
let (run_directory, _) = match write_stack(
&stack,
repo.as_ref(),
git_token,
@@ -207,53 +178,16 @@ 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
};
let env_file_args = env_file_args(
env_file_path,
&stack.config.additional_env_files,
)?;
// Uses 'docker stack config' command to extract services (including image)
// after performing interpolation
{
let command =
format!("{env_file_args}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 || !env_file_args.is_empty() {
KomodoCommandMode::Shell
} else {
KomodoCommandMode::Standard
};
let command = format!("docker stack config -c {file_args}",);
let span = info_span!("GetStackConfig", command);
let Some(config_log) = run_komodo_command_with_sanitization(
"Stack Config",
run_directory.as_path(),
command,
mode,
KomodoCommandMode::Standard,
&replacers,
)
.instrument(span)
@@ -297,9 +231,8 @@ impl Resolve<crate::api::Args> for DeploySwarmStack {
}
// Run stack deploy
let mut command = format!(
"{env_file_args}docker stack deploy --detach=true -c {file_args}"
);
let mut command =
format!("docker stack deploy --detach=false -c {file_args}");
if use_with_registry_auth {
command += " --with-registry-auth";
}
@@ -307,18 +240,19 @@ impl Resolve<crate::api::Args> for DeploySwarmStack {
write!(&mut command, " {project_name}")?;
// Apply compose cmd wrapper if configured
let (command, _) = match maybe_wrap_command(
command,
&compose_cmd_wrapper,
wrapper_include,
"deploy",
) {
Ok(result) => result,
Err(log) => {
res.logs.push(log);
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(),
));
return Ok(res);
}
};
command =
compose_cmd_wrapper.replace("[[COMPOSE_COMMAND]]", &command);
}
let span = info_span!("ExecuteStackDeploy");
let Some(log) = run_komodo_command_with_sanitization(
@@ -359,43 +293,6 @@ impl Resolve<crate::api::Args> for DeploySwarmStack {
}
}
/// Prefix docker stack deploy command.
///
/// Produces either
/// - Empty string (no env files defined)
/// - 'set -a && . .env1 && . .env2 && '
fn env_file_args(
env_file_path: Option<&str>,
additional_env_files: &[AdditionalEnvFile],
) -> anyhow::Result<String> {
let mut res = String::new();
// Add additional env files (except komodo's own, which comes last)
for file in additional_env_files
.iter()
.filter(|f| env_file_path != Some(f.path.as_str()))
{
let path = &file.path;
write!(res, ". {path} && ").with_context(|| {
format!("Failed to write env source arg for {path}")
})?;
}
// Add komodo's env file last for highest priority
if let Some(file) = env_file_path {
write!(res, ". {file} && ").with_context(|| {
format!("Failed to write env source arg for {file}")
})?;
}
if !res.is_empty() {
// Add 'set -a' so vars are auto exported to child 'docker stack' process.
Ok(format!("set -a && {res}"))
} else {
Ok(res)
}
}
#[instrument("RemoveStack", skip(res))]
async fn remove_stack(
stack: &str,
+10 -40
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, optional_string,
KOMODO_EXIT_CODE, NoData,
terminal::{Terminal, TerminalStdinMessage, TerminalTarget},
};
use mogh_resolver::Resolve;
@@ -52,32 +52,20 @@ impl Resolve<crate::api::Args> for CreateServerTerminal {
async fn resolve(
self,
args: &crate::api::Args,
) -> anyhow::Result<Terminal> {
) -> anyhow::Result<NoData> {
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
.and_then(optional_string)
.unwrap_or_else(|| format!("term-{}", existing.len())),
self.name,
TerminalTarget::Server { server: None },
self.command,
self.recreate,
)
.await
.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,
})
.map(|_| NoData {})
}
}
@@ -99,7 +87,7 @@ impl Resolve<crate::api::Args> for CreateContainerExecTerminal {
async fn resolve(
self,
args: &crate::api::Args,
) -> anyhow::Result<Terminal> {
) -> anyhow::Result<NoData> {
if periphery_config().disable_container_terminals {
return Err(anyhow!(
"Container Terminals are disabled in the Periphery config"
@@ -118,23 +106,14 @@ 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.and_then(optional_string).unwrap_or_else(|| {
format!("exec-{container}-{}", existing.len())
}),
name,
target,
Some(format!("docker exec -it {container} {command}")),
recreate,
)
.await
.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,
})
.map(|_| NoData {})
}
}
@@ -155,7 +134,7 @@ impl Resolve<crate::api::Args> for CreateContainerAttachTerminal {
async fn resolve(
self,
args: &crate::api::Args,
) -> anyhow::Result<Terminal> {
) -> anyhow::Result<NoData> {
if periphery_config().disable_container_terminals {
return Err(anyhow!(
"Container Terminals are disabled in the Periphery config"
@@ -172,23 +151,14 @@ 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.and_then(optional_string).unwrap_or_else(|| {
format!("attach-{container}-{}", existing.len())
}),
name,
target,
Some(format!("docker attach {container} --sig-proxy=false")),
recreate,
)
.await
.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,
})
.map(|_| NoData {})
}
}
-3
View File
@@ -144,9 +144,6 @@ pub fn periphery_config() -> &'static PeripheryConfig {
ansi: env
.periphery_logging_ansi
.unwrap_or(config.logging.ansi),
timestamps: env
.periphery_logging_timestamps
.unwrap_or(config.logging.timestamps),
otlp_endpoint: env
.periphery_logging_otlp_endpoint
.unwrap_or(config.logging.otlp_endpoint),
+46 -46
View File
@@ -461,80 +461,80 @@ impl DockerClient {
}
fn convert_summary_container_state(
state: bollard::config::ContainerSummaryStateEnum,
state: bollard::secret::ContainerSummaryStateEnum,
) -> ContainerStateStatusEnum {
match state {
bollard::config::ContainerSummaryStateEnum::EMPTY => {
bollard::secret::ContainerSummaryStateEnum::EMPTY => {
ContainerStateStatusEnum::Empty
}
bollard::config::ContainerSummaryStateEnum::CREATED => {
bollard::secret::ContainerSummaryStateEnum::CREATED => {
ContainerStateStatusEnum::Created
}
bollard::config::ContainerSummaryStateEnum::RUNNING => {
bollard::secret::ContainerSummaryStateEnum::RUNNING => {
ContainerStateStatusEnum::Running
}
bollard::config::ContainerSummaryStateEnum::PAUSED => {
bollard::secret::ContainerSummaryStateEnum::PAUSED => {
ContainerStateStatusEnum::Paused
}
bollard::config::ContainerSummaryStateEnum::RESTARTING => {
bollard::secret::ContainerSummaryStateEnum::RESTARTING => {
ContainerStateStatusEnum::Restarting
}
bollard::config::ContainerSummaryStateEnum::EXITED => {
bollard::secret::ContainerSummaryStateEnum::EXITED => {
ContainerStateStatusEnum::Exited
}
bollard::config::ContainerSummaryStateEnum::REMOVING => {
bollard::secret::ContainerSummaryStateEnum::REMOVING => {
ContainerStateStatusEnum::Removing
}
bollard::config::ContainerSummaryStateEnum::DEAD => {
bollard::secret::ContainerSummaryStateEnum::DEAD => {
ContainerStateStatusEnum::Dead
}
}
}
fn convert_container_state_status(
state: bollard::config::ContainerStateStatusEnum,
state: bollard::secret::ContainerStateStatusEnum,
) -> ContainerStateStatusEnum {
match state {
bollard::config::ContainerStateStatusEnum::EMPTY => {
bollard::secret::ContainerStateStatusEnum::EMPTY => {
ContainerStateStatusEnum::Empty
}
bollard::config::ContainerStateStatusEnum::CREATED => {
bollard::secret::ContainerStateStatusEnum::CREATED => {
ContainerStateStatusEnum::Created
}
bollard::config::ContainerStateStatusEnum::RUNNING => {
bollard::secret::ContainerStateStatusEnum::RUNNING => {
ContainerStateStatusEnum::Running
}
bollard::config::ContainerStateStatusEnum::PAUSED => {
bollard::secret::ContainerStateStatusEnum::PAUSED => {
ContainerStateStatusEnum::Paused
}
bollard::config::ContainerStateStatusEnum::RESTARTING => {
bollard::secret::ContainerStateStatusEnum::RESTARTING => {
ContainerStateStatusEnum::Restarting
}
bollard::config::ContainerStateStatusEnum::EXITED => {
bollard::secret::ContainerStateStatusEnum::EXITED => {
ContainerStateStatusEnum::Exited
}
bollard::config::ContainerStateStatusEnum::REMOVING => {
bollard::secret::ContainerStateStatusEnum::REMOVING => {
ContainerStateStatusEnum::Removing
}
bollard::config::ContainerStateStatusEnum::DEAD => {
bollard::secret::ContainerStateStatusEnum::DEAD => {
ContainerStateStatusEnum::Dead
}
}
}
fn convert_port_type(
typ: bollard::config::PortSummaryTypeEnum,
typ: bollard::secret::PortSummaryTypeEnum,
) -> PortTypeEnum {
match typ {
bollard::config::PortSummaryTypeEnum::EMPTY => {
bollard::secret::PortSummaryTypeEnum::EMPTY => {
PortTypeEnum::EMPTY
}
bollard::config::PortSummaryTypeEnum::TCP => PortTypeEnum::TCP,
bollard::config::PortSummaryTypeEnum::UDP => PortTypeEnum::UDP,
bollard::config::PortSummaryTypeEnum::SCTP => PortTypeEnum::SCTP,
bollard::secret::PortSummaryTypeEnum::TCP => PortTypeEnum::TCP,
bollard::secret::PortSummaryTypeEnum::UDP => PortTypeEnum::UDP,
bollard::secret::PortSummaryTypeEnum::SCTP => PortTypeEnum::SCTP,
}
}
fn convert_port(port: bollard::config::PortSummary) -> Port {
fn convert_port(port: bollard::secret::PortSummary) -> Port {
Port {
ip: port.ip,
private_port: port.private_port,
@@ -544,27 +544,27 @@ fn convert_port(port: bollard::config::PortSummary) -> Port {
}
fn convert_health_status(
status: bollard::config::HealthStatusEnum,
status: bollard::secret::HealthStatusEnum,
) -> HealthStatusEnum {
match status {
bollard::config::HealthStatusEnum::EMPTY => {
bollard::secret::HealthStatusEnum::EMPTY => {
HealthStatusEnum::Empty
}
bollard::config::HealthStatusEnum::NONE => HealthStatusEnum::None,
bollard::config::HealthStatusEnum::STARTING => {
bollard::secret::HealthStatusEnum::NONE => HealthStatusEnum::None,
bollard::secret::HealthStatusEnum::STARTING => {
HealthStatusEnum::Starting
}
bollard::config::HealthStatusEnum::HEALTHY => {
bollard::secret::HealthStatusEnum::HEALTHY => {
HealthStatusEnum::Healthy
}
bollard::config::HealthStatusEnum::UNHEALTHY => {
bollard::secret::HealthStatusEnum::UNHEALTHY => {
HealthStatusEnum::Unhealthy
}
}
}
fn convert_health_check_result(
check: bollard::config::HealthcheckResult,
check: bollard::secret::HealthcheckResult,
) -> HealthcheckResult {
HealthcheckResult {
start: check.start,
@@ -575,57 +575,57 @@ fn convert_health_check_result(
}
fn convert_restart_policy(
policy: bollard::config::RestartPolicyNameEnum,
policy: bollard::secret::RestartPolicyNameEnum,
) -> RestartPolicyNameEnum {
match policy {
bollard::config::RestartPolicyNameEnum::EMPTY => {
bollard::secret::RestartPolicyNameEnum::EMPTY => {
RestartPolicyNameEnum::Empty
}
bollard::config::RestartPolicyNameEnum::NO => {
bollard::secret::RestartPolicyNameEnum::NO => {
RestartPolicyNameEnum::No
}
bollard::config::RestartPolicyNameEnum::ALWAYS => {
bollard::secret::RestartPolicyNameEnum::ALWAYS => {
RestartPolicyNameEnum::Always
}
bollard::config::RestartPolicyNameEnum::UNLESS_STOPPED => {
bollard::secret::RestartPolicyNameEnum::UNLESS_STOPPED => {
RestartPolicyNameEnum::UnlessStopped
}
bollard::config::RestartPolicyNameEnum::ON_FAILURE => {
bollard::secret::RestartPolicyNameEnum::ON_FAILURE => {
RestartPolicyNameEnum::OnFailure
}
}
}
fn convert_cgroupns_mode(
mode: bollard::config::HostConfigCgroupnsModeEnum,
mode: bollard::secret::HostConfigCgroupnsModeEnum,
) -> HostConfigCgroupnsModeEnum {
match mode {
bollard::config::HostConfigCgroupnsModeEnum::EMPTY => {
bollard::secret::HostConfigCgroupnsModeEnum::EMPTY => {
HostConfigCgroupnsModeEnum::Empty
}
bollard::config::HostConfigCgroupnsModeEnum::PRIVATE => {
bollard::secret::HostConfigCgroupnsModeEnum::PRIVATE => {
HostConfigCgroupnsModeEnum::Private
}
bollard::config::HostConfigCgroupnsModeEnum::HOST => {
bollard::secret::HostConfigCgroupnsModeEnum::HOST => {
HostConfigCgroupnsModeEnum::Host
}
}
}
fn convert_isolation_mode(
isolation: bollard::config::HostConfigIsolationEnum,
isolation: bollard::secret::HostConfigIsolationEnum,
) -> HostConfigIsolationEnum {
match isolation {
bollard::config::HostConfigIsolationEnum::EMPTY => {
bollard::secret::HostConfigIsolationEnum::EMPTY => {
HostConfigIsolationEnum::Empty
}
bollard::config::HostConfigIsolationEnum::DEFAULT => {
bollard::secret::HostConfigIsolationEnum::DEFAULT => {
HostConfigIsolationEnum::Default
}
bollard::config::HostConfigIsolationEnum::PROCESS => {
bollard::secret::HostConfigIsolationEnum::PROCESS => {
HostConfigIsolationEnum::Process
}
bollard::config::HostConfigIsolationEnum::HYPERV => {
bollard::secret::HostConfigIsolationEnum::HYPERV => {
HostConfigIsolationEnum::Hyperv
}
}
+8 -7
View File
@@ -29,7 +29,8 @@ impl DockerClient {
});
let name = image
.repo_tags
.first()
.iter()
.next()
.cloned()
.unwrap_or_else(|| image.id.clone());
ImageListItem {
@@ -72,10 +73,10 @@ impl DockerClient {
content: manifest.size.content,
},
kind: manifest.kind.map(|kind| match kind {
bollard::config::ImageManifestSummaryKindEnum::EMPTY => ImageManifestSummaryKindEnum::Empty,
bollard::config::ImageManifestSummaryKindEnum::IMAGE => ImageManifestSummaryKindEnum::Image,
bollard::config::ImageManifestSummaryKindEnum::ATTESTATION => ImageManifestSummaryKindEnum::Attestation,
bollard::config::ImageManifestSummaryKindEnum::UNKNOWN => ImageManifestSummaryKindEnum::Unknown,
bollard::secret::ImageManifestSummaryKindEnum::EMPTY => ImageManifestSummaryKindEnum::Empty,
bollard::secret::ImageManifestSummaryKindEnum::IMAGE => ImageManifestSummaryKindEnum::Image,
bollard::secret::ImageManifestSummaryKindEnum::ATTESTATION => ImageManifestSummaryKindEnum::Attestation,
bollard::secret::ImageManifestSummaryKindEnum::UNKNOWN => ImageManifestSummaryKindEnum::Unknown,
}),
image_data: manifest.image_data.map(|data| {
ImageManifestSummaryImageData {
@@ -159,7 +160,7 @@ impl DockerClient {
}
fn convert_oci_descriptor(
descriptor: bollard::config::OciDescriptor,
descriptor: bollard::secret::OciDescriptor,
) -> OciDescriptor {
OciDescriptor {
media_type: descriptor.media_type,
@@ -174,7 +175,7 @@ fn convert_oci_descriptor(
}
fn convert_oci_platform(
platform: bollard::config::OciPlatform,
platform: bollard::secret::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::config::MountTypeEnum,
typ: bollard::secret::MountTypeEnum,
) -> MountTypeEnum {
match typ {
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,
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,
}
}
fn convert_mount_propogation(
propogation: bollard::config::MountBindOptionsPropagationEnum,
propogation: bollard::secret::MountBindOptionsPropagationEnum,
) -> MountBindOptionsPropagationEnum {
match propogation {
bollard::config::MountBindOptionsPropagationEnum::EMPTY => {
bollard::secret::MountBindOptionsPropagationEnum::EMPTY => {
MountBindOptionsPropagationEnum::Empty
}
bollard::config::MountBindOptionsPropagationEnum::PRIVATE => {
bollard::secret::MountBindOptionsPropagationEnum::PRIVATE => {
MountBindOptionsPropagationEnum::Private
}
bollard::config::MountBindOptionsPropagationEnum::RPRIVATE => {
bollard::secret::MountBindOptionsPropagationEnum::RPRIVATE => {
MountBindOptionsPropagationEnum::Rprivate
}
bollard::config::MountBindOptionsPropagationEnum::SHARED => {
bollard::secret::MountBindOptionsPropagationEnum::SHARED => {
MountBindOptionsPropagationEnum::Shared
}
bollard::config::MountBindOptionsPropagationEnum::RSHARED => {
bollard::secret::MountBindOptionsPropagationEnum::RSHARED => {
MountBindOptionsPropagationEnum::Rshared
}
bollard::config::MountBindOptionsPropagationEnum::SLAVE => {
bollard::secret::MountBindOptionsPropagationEnum::SLAVE => {
MountBindOptionsPropagationEnum::Slave
}
bollard::config::MountBindOptionsPropagationEnum::RSLAVE => {
bollard::secret::MountBindOptionsPropagationEnum::RSLAVE => {
MountBindOptionsPropagationEnum::Rslave
}
}
}
fn convert_mount_point_type(
typ: bollard::config::MountPointTypeEnum,
typ: bollard::secret::MountPointTypeEnum,
) -> MountTypeEnum {
match typ {
bollard::config::MountPointTypeEnum::EMPTY => {
bollard::secret::MountPointTypeEnum::EMPTY => {
MountTypeEnum::Empty
}
bollard::config::MountPointTypeEnum::BIND => MountTypeEnum::Bind,
bollard::config::MountPointTypeEnum::VOLUME => {
bollard::secret::MountPointTypeEnum::BIND => MountTypeEnum::Bind,
bollard::secret::MountPointTypeEnum::VOLUME => {
MountTypeEnum::Volume
}
bollard::config::MountPointTypeEnum::IMAGE => {
bollard::secret::MountPointTypeEnum::IMAGE => {
MountTypeEnum::Image
}
bollard::config::MountPointTypeEnum::TMPFS => {
bollard::secret::MountPointTypeEnum::TMPFS => {
MountTypeEnum::Tmpfs
}
bollard::config::MountPointTypeEnum::NPIPE => {
bollard::secret::MountPointTypeEnum::NPIPE => {
MountTypeEnum::Npipe
}
bollard::config::MountPointTypeEnum::CLUSTER => {
bollard::secret::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::config::EndpointPortConfigProtocolEnum::EMPTY => EndpointPortConfigProtocolEnum::EMPTY,
bollard::config::EndpointPortConfigProtocolEnum::TCP => EndpointPortConfigProtocolEnum::TCP,
bollard::config::EndpointPortConfigProtocolEnum::UDP => EndpointPortConfigProtocolEnum::UDP,
bollard::config::EndpointPortConfigProtocolEnum::SCTP => EndpointPortConfigProtocolEnum::SCTP,
bollard::secret::EndpointPortConfigProtocolEnum::EMPTY => EndpointPortConfigProtocolEnum::EMPTY,
bollard::secret::EndpointPortConfigProtocolEnum::TCP => EndpointPortConfigProtocolEnum::TCP,
bollard::secret::EndpointPortConfigProtocolEnum::UDP => EndpointPortConfigProtocolEnum::UDP,
bollard::secret::EndpointPortConfigProtocolEnum::SCTP => EndpointPortConfigProtocolEnum::SCTP,
}),
target_port: port.target_port,
published_port: port.published_port,
publish_mode: port.publish_mode.map(|protocol| match protocol {
bollard::config::EndpointPortConfigPublishModeEnum::EMPTY => EndpointPortConfigPublishModeEnum::EMPTY,
bollard::config::EndpointPortConfigPublishModeEnum::INGRESS => EndpointPortConfigPublishModeEnum::INGRESS,
bollard::config::EndpointPortConfigPublishModeEnum::HOST => EndpointPortConfigPublishModeEnum::HOST,
bollard::secret::EndpointPortConfigPublishModeEnum::EMPTY => EndpointPortConfigPublishModeEnum::EMPTY,
bollard::secret::EndpointPortConfigPublishModeEnum::INGRESS => EndpointPortConfigPublishModeEnum::INGRESS,
bollard::secret::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::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY,
bollard::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT,
bollard::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED => TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED,
bollard::config::TaskSpecContainerSpecPrivilegesSeccompModeEnum::CUSTOM => TaskSpecContainerSpecPrivilegesSeccompModeEnum::CUSTOM,
bollard::secret::TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesSeccompModeEnum::EMPTY,
bollard::secret::TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesSeccompModeEnum::DEFAULT,
bollard::secret::TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED => TaskSpecContainerSpecPrivilegesSeccompModeEnum::UNCONFINED,
bollard::secret::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::config::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY,
bollard::config::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT,
bollard::config::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DISABLED => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DISABLED,
bollard::secret::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::EMPTY,
bollard::secret::TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT => TaskSpecContainerSpecPrivilegesAppArmorModeEnum::DEFAULT,
bollard::secret::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::config::TaskSpecContainerSpecIsolationEnum::DEFAULT => TaskSpecContainerSpecIsolationEnum::DEFAULT,
bollard::config::TaskSpecContainerSpecIsolationEnum::PROCESS => TaskSpecContainerSpecIsolationEnum::PROCESS,
bollard::config::TaskSpecContainerSpecIsolationEnum::HYPERV => TaskSpecContainerSpecIsolationEnum::HYPERV,
bollard::config::TaskSpecContainerSpecIsolationEnum::EMPTY => TaskSpecContainerSpecIsolationEnum::EMPTY,
bollard::secret::TaskSpecContainerSpecIsolationEnum::DEFAULT => TaskSpecContainerSpecIsolationEnum::DEFAULT,
bollard::secret::TaskSpecContainerSpecIsolationEnum::PROCESS => TaskSpecContainerSpecIsolationEnum::PROCESS,
bollard::secret::TaskSpecContainerSpecIsolationEnum::HYPERV => TaskSpecContainerSpecIsolationEnum::HYPERV,
bollard::secret::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::config::TaskSpecRestartPolicyConditionEnum,
condition: bollard::secret::TaskSpecRestartPolicyConditionEnum,
) -> TaskSpecRestartPolicyConditionEnum {
match condition {
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,
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,
}
}
+21 -21
View File
@@ -51,24 +51,24 @@ impl DockerClient {
fn convert_node_list_item(
node: bollard::models::Node,
) -> SwarmNodeListItem {
let (name, role, availability, labels) = node
let (name, role, availability) = node
.spec
.map(|spec| {
(
spec.name,
spec.role.map(convert_role),
spec.availability.map(convert_availability),
spec.labels,
)
})
.unwrap_or_default();
SwarmNodeListItem {
id: node.id,
name,
hostname: node.description.and_then(|d| d.hostname),
role,
availability,
labels,
hostname: node
.description
.and_then(|description| description.hostname),
state: node
.status
.and_then(|status| status.state.map(convert_state)),
@@ -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::config::Reachability::UNKNOWN => {
bollard::secret::Reachability::UNKNOWN => {
NodeReachability::UNKNOWN
}
bollard::config::Reachability::UNREACHABLE => {
bollard::secret::Reachability::UNREACHABLE => {
NodeReachability::UNREACHABLE
}
bollard::config::Reachability::REACHABLE => {
bollard::secret::Reachability::REACHABLE => {
NodeReachability::REACHABLE
}
},
@@ -143,46 +143,46 @@ fn convert_node_spec(spec: bollard::models::NodeSpec) -> NodeSpec {
}
fn convert_role(
role: bollard::config::NodeSpecRoleEnum,
role: bollard::secret::NodeSpecRoleEnum,
) -> NodeSpecRoleEnum {
match role {
bollard::config::NodeSpecRoleEnum::EMPTY => {
bollard::secret::NodeSpecRoleEnum::EMPTY => {
NodeSpecRoleEnum::EMPTY
}
bollard::config::NodeSpecRoleEnum::WORKER => {
bollard::secret::NodeSpecRoleEnum::WORKER => {
NodeSpecRoleEnum::WORKER
}
bollard::config::NodeSpecRoleEnum::MANAGER => {
bollard::secret::NodeSpecRoleEnum::MANAGER => {
NodeSpecRoleEnum::MANAGER
}
}
}
fn convert_availability(
availability: bollard::config::NodeSpecAvailabilityEnum,
availability: bollard::secret::NodeSpecAvailabilityEnum,
) -> NodeSpecAvailabilityEnum {
match availability {
bollard::config::NodeSpecAvailabilityEnum::EMPTY => {
bollard::secret::NodeSpecAvailabilityEnum::EMPTY => {
NodeSpecAvailabilityEnum::EMPTY
}
bollard::config::NodeSpecAvailabilityEnum::ACTIVE => {
bollard::secret::NodeSpecAvailabilityEnum::ACTIVE => {
NodeSpecAvailabilityEnum::ACTIVE
}
bollard::config::NodeSpecAvailabilityEnum::PAUSE => {
bollard::secret::NodeSpecAvailabilityEnum::PAUSE => {
NodeSpecAvailabilityEnum::PAUSE
}
bollard::config::NodeSpecAvailabilityEnum::DRAIN => {
bollard::secret::NodeSpecAvailabilityEnum::DRAIN => {
NodeSpecAvailabilityEnum::DRAIN
}
}
}
fn convert_state(state: bollard::config::NodeState) -> NodeState {
fn convert_state(state: bollard::secret::NodeState) -> NodeState {
match state {
bollard::config::NodeState::UNKNOWN => NodeState::UNKNOWN,
bollard::config::NodeState::DOWN => NodeState::DOWN,
bollard::config::NodeState::READY => NodeState::READY,
bollard::config::NodeState::DISCONNECTED => {
bollard::secret::NodeState::UNKNOWN => NodeState::UNKNOWN,
bollard::secret::NodeState::DOWN => NodeState::DOWN,
bollard::secret::NodeState::READY => NodeState::READY,
bollard::secret::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(convert_service_list_item)
.map(|service| convert_service_list_item(service))
.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::config::ServiceSpecUpdateConfigFailureActionEnum::EMPTY => ServiceSpecUpdateConfigFailureActionEnum::EMPTY,
bollard::config::ServiceSpecUpdateConfigFailureActionEnum::CONTINUE => ServiceSpecUpdateConfigFailureActionEnum::CONTINUE,
bollard::config::ServiceSpecUpdateConfigFailureActionEnum::PAUSE => ServiceSpecUpdateConfigFailureActionEnum::PAUSE,
bollard::config::ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK => ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK,
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::EMPTY => ServiceSpecUpdateConfigFailureActionEnum::EMPTY,
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::CONTINUE => ServiceSpecUpdateConfigFailureActionEnum::CONTINUE,
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::PAUSE => ServiceSpecUpdateConfigFailureActionEnum::PAUSE,
bollard::secret::ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK => ServiceSpecUpdateConfigFailureActionEnum::ROLLBACK,
}),
monitor: config.monitor,
max_failure_ratio: config.max_failure_ratio,
order: config.order.map(|order| match order {
bollard::config::ServiceSpecUpdateConfigOrderEnum::EMPTY => ServiceSpecUpdateConfigOrderEnum::EMPTY,
bollard::config::ServiceSpecUpdateConfigOrderEnum::STOP_FIRST => ServiceSpecUpdateConfigOrderEnum::STOP_FIRST,
bollard::config::ServiceSpecUpdateConfigOrderEnum::START_FIRST => ServiceSpecUpdateConfigOrderEnum::START_FIRST,
bollard::secret::ServiceSpecUpdateConfigOrderEnum::EMPTY => ServiceSpecUpdateConfigOrderEnum::EMPTY,
bollard::secret::ServiceSpecUpdateConfigOrderEnum::STOP_FIRST => ServiceSpecUpdateConfigOrderEnum::STOP_FIRST,
bollard::secret::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::config::ServiceSpecRollbackConfigFailureActionEnum::EMPTY => ServiceSpecRollbackConfigFailureActionEnum::EMPTY,
bollard::config::ServiceSpecRollbackConfigFailureActionEnum::CONTINUE => ServiceSpecRollbackConfigFailureActionEnum::CONTINUE,
bollard::config::ServiceSpecRollbackConfigFailureActionEnum::PAUSE => ServiceSpecRollbackConfigFailureActionEnum::PAUSE,
bollard::secret::ServiceSpecRollbackConfigFailureActionEnum::EMPTY => ServiceSpecRollbackConfigFailureActionEnum::EMPTY,
bollard::secret::ServiceSpecRollbackConfigFailureActionEnum::CONTINUE => ServiceSpecRollbackConfigFailureActionEnum::CONTINUE,
bollard::secret::ServiceSpecRollbackConfigFailureActionEnum::PAUSE => ServiceSpecRollbackConfigFailureActionEnum::PAUSE,
}),
monitor: config.monitor,
max_failure_ratio: config.max_failure_ratio,
order: config.order.map(|order| match order {
bollard::config::ServiceSpecRollbackConfigOrderEnum::EMPTY => ServiceSpecRollbackConfigOrderEnum::EMPTY,
bollard::config::ServiceSpecRollbackConfigOrderEnum::STOP_FIRST => ServiceSpecRollbackConfigOrderEnum::STOP_FIRST,
bollard::config::ServiceSpecRollbackConfigOrderEnum::START_FIRST => ServiceSpecRollbackConfigOrderEnum::START_FIRST,
bollard::secret::ServiceSpecRollbackConfigOrderEnum::EMPTY => ServiceSpecRollbackConfigOrderEnum::EMPTY,
bollard::secret::ServiceSpecRollbackConfigOrderEnum::STOP_FIRST => ServiceSpecRollbackConfigOrderEnum::STOP_FIRST,
bollard::secret::ServiceSpecRollbackConfigOrderEnum::START_FIRST => ServiceSpecRollbackConfigOrderEnum::START_FIRST,
}),
}
}),
@@ -408,13 +408,13 @@ fn convert_endpoint_spec(
) -> EndpointSpec {
EndpointSpec {
mode: spec.mode.map(|mode| match mode {
bollard::config::EndpointSpecModeEnum::EMPTY => {
bollard::secret::EndpointSpecModeEnum::EMPTY => {
EndpointSpecModeEnum::EMPTY
}
bollard::config::EndpointSpecModeEnum::VIP => {
bollard::secret::EndpointSpecModeEnum::VIP => {
EndpointSpecModeEnum::VIP
}
bollard::config::EndpointSpecModeEnum::DNSRR => {
bollard::secret::EndpointSpecModeEnum::DNSRR => {
EndpointSpecModeEnum::DNSRR
}
}),
@@ -423,15 +423,15 @@ fn convert_endpoint_spec(
}
fn convert_state(
state: bollard::config::ServiceUpdateStatusStateEnum,
state: bollard::secret::ServiceUpdateStatusStateEnum,
) -> ServiceUpdateStatusStateEnum {
match state {
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,
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,
}
}
+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::config::SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY => SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY,
bollard::config::SwarmSpecCaConfigExternalCasProtocolEnum::CFSSL => SwarmSpecCaConfigExternalCasProtocolEnum::CFSSL,
bollard::secret::SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY => SwarmSpecCaConfigExternalCasProtocolEnum::EMPTY,
bollard::secret::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::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,
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,
}
}
+23 -23
View File
@@ -21,13 +21,13 @@ impl DockerClient {
let scope = volume
.scope
.map(|scope| match scope {
bollard::config::VolumeScopeEnum::EMPTY => {
bollard::secret::VolumeScopeEnum::EMPTY => {
VolumeScopeEnum::Empty
}
bollard::config::VolumeScopeEnum::LOCAL => {
bollard::secret::VolumeScopeEnum::LOCAL => {
VolumeScopeEnum::Local
}
bollard::config::VolumeScopeEnum::GLOBAL => {
bollard::secret::VolumeScopeEnum::GLOBAL => {
VolumeScopeEnum::Global
}
})
@@ -69,13 +69,13 @@ impl DockerClient {
scope: volume
.scope
.map(|scope| match scope {
bollard::config::VolumeScopeEnum::EMPTY => {
bollard::secret::VolumeScopeEnum::EMPTY => {
VolumeScopeEnum::Empty
}
bollard::config::VolumeScopeEnum::LOCAL => {
bollard::secret::VolumeScopeEnum::LOCAL => {
VolumeScopeEnum::Local
}
bollard::config::VolumeScopeEnum::GLOBAL => {
bollard::secret::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::config::ClusterVolumeSpecAccessModeScopeEnum::EMPTY => ClusterVolumeSpecAccessModeScopeEnum::Empty,
bollard::config::ClusterVolumeSpecAccessModeScopeEnum::SINGLE => ClusterVolumeSpecAccessModeScopeEnum::Single,
bollard::config::ClusterVolumeSpecAccessModeScopeEnum::MULTI => ClusterVolumeSpecAccessModeScopeEnum::Multi,
bollard::secret::ClusterVolumeSpecAccessModeScopeEnum::EMPTY => ClusterVolumeSpecAccessModeScopeEnum::Empty,
bollard::secret::ClusterVolumeSpecAccessModeScopeEnum::SINGLE => ClusterVolumeSpecAccessModeScopeEnum::Single,
bollard::secret::ClusterVolumeSpecAccessModeScopeEnum::MULTI => ClusterVolumeSpecAccessModeScopeEnum::Multi,
}).unwrap_or_default(),
sharing: mode.sharing.map(|sharing| match sharing {
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,
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,
}).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::config::ClusterVolumeSpecAccessModeAvailabilityEnum::EMPTY => ClusterVolumeSpecAccessModeAvailabilityEnum::Empty,
bollard::config::ClusterVolumeSpecAccessModeAvailabilityEnum::ACTIVE => ClusterVolumeSpecAccessModeAvailabilityEnum::Active,
bollard::config::ClusterVolumeSpecAccessModeAvailabilityEnum::PAUSE => ClusterVolumeSpecAccessModeAvailabilityEnum::Pause,
bollard::config::ClusterVolumeSpecAccessModeAvailabilityEnum::DRAIN => ClusterVolumeSpecAccessModeAvailabilityEnum::Drain,
bollard::secret::ClusterVolumeSpecAccessModeAvailabilityEnum::EMPTY => ClusterVolumeSpecAccessModeAvailabilityEnum::Empty,
bollard::secret::ClusterVolumeSpecAccessModeAvailabilityEnum::ACTIVE => ClusterVolumeSpecAccessModeAvailabilityEnum::Active,
bollard::secret::ClusterVolumeSpecAccessModeAvailabilityEnum::PAUSE => ClusterVolumeSpecAccessModeAvailabilityEnum::Pause,
bollard::secret::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::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,
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,
}).unwrap_or_default(),
publish_context: status.publish_context.unwrap_or_default(),
})
-1
View File
@@ -183,7 +183,6 @@ pub enum Execution {
// SWARM
RemoveSwarmNodes(RemoveSwarmNodes),
UpdateSwarmNode(UpdateSwarmNode),
RemoveSwarmStacks(RemoveSwarmStacks),
RemoveSwarmServices(RemoveSwarmServices),
CreateSwarmConfig(CreateSwarmConfig),
@@ -7,7 +7,6 @@ use crate::api::execute;
paths(
// swarm
execute::remove_swarm_nodes,
execute::update_swarm_node,
execute::remove_swarm_stacks,
execute::remove_swarm_services,
execute::create_swarm_config,
+1 -47
View File
@@ -4,11 +4,7 @@ use serde::{Deserialize, Serialize};
use typeshare::typeshare;
use crate::{
api::execute::KomodoExecuteRequest,
entities::{
docker::node::{NodeSpecAvailabilityEnum, NodeSpecRoleEnum},
update::Update,
},
api::execute::KomodoExecuteRequest, entities::update::Update,
};
// ========
@@ -49,48 +45,6 @@ pub struct RemoveSwarmNodes {
pub force: bool,
}
#[cfg(feature = "utoipa")]
#[utoipa::path(
post,
path = "/UpdateSwarmNode",
description = "Update a swarm node's availability, labels, and role.",
request_body(content = UpdateSwarmNode),
responses(
(status = 200, description = "The update", body = Update),
),
)]
pub fn update_swarm_node() {}
/// `docker node update [OPTIONS] NODE`
///
/// https://docs.docker.com/reference/cli/docker/node/update/
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, PartialEq, Resolve, Parser,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[empty_traits(KomodoExecuteRequest)]
#[response(Update)]
#[error(mogh_error::Error)]
pub struct UpdateSwarmNode {
/// Name or id
pub swarm: String,
/// Node hostname or id
pub node: String,
/// Update the node's availability: 'active', 'pause', or 'drain'
#[arg(long, short = 'a')]
pub availability: Option<NodeSpecAvailabilityEnum>,
/// Add labels to node (`key=value`).
#[arg(long, short = 'l')]
pub label_add: Option<Vec<String>>,
/// Add labels to node (`key=value`). (alias: `lr`)
#[arg(long, alias = "lr")]
pub label_rm: Option<Vec<String>>,
/// Update the node's role: 'worker' or 'manager'
#[arg(long, short = 'r')]
pub role: Option<NodeSpecRoleEnum>,
}
// =========
// = Stack =
// =========

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