Files
komodo/scripts/setup-periphery.py
Maxwell Becker 8708f0f600 2.3.0 (#1520)
* dockerfile builds use latest rust 1.96.0

* bump rust and js dependencies

* deploy 2.3.0-dev-1

* omnisearch clear on close option (default true), fix omnisearch border radius cutting off search input

* fix resource description responsive overflow in some screen size

* kill process group

* Start wiring through shell timeout / external cancel options

* deploy 2.3.0-dev-2

* implement CommandOptions (timeout / cancel ability) throughout shell usage

* Add timeouts to read child commands

* deploy 2.3.0-dev-3

* remove periphery custom_timeout option, it doesn't function as timeout as expected

* customize command timeouts

* Ensure git is installed for clear error message

* deploy 2.3.0-dev-4

* deploy 2.3.0-dev-5

* deploy 2.3.0-dev-6

* swarm completed in roadmap

* unnecessary line

* Komodo v2 march 2026

* remove debub container ports logs

* remove log view console log

* Fix deployment tabs disappear

* align other resource store tab per resource id

* disable terminal tab when attached to swarm

* List All Docker Containers supports wildcard container name matching

* improve container pagination situation

* deploy 2.3.0-dev-7

* fix container data table search slowness

* deploy 2.3.0-dev-8

* ListAllStackServices, add stack services to omni search, All containers filter by tags (based on server)

* deploy 2.3.0-dev-9

* service icon correct size

* list all containers / services support filtering by state

* get latest image digest timeout 10s

* deploy 2.3.0-dev-10

* send keepalive pings on user websockets to survive idle proxy timeouts (#1486)

* bump mantine and other UI deps

* deploy 2.3.0-dev-11

* fix containers page server filter

* show server config always if no swarms exist

* DeleteTerminal: fix incoming stack / deployment names to ids internally

* single builder distribute to multiple specified servers

* deploy 2.3.0-dev-12

* fix server type builder config comment

* fix builder toml server_ids => server/s

* sync: fix alerter resources / except_resources using ids instead of names

* fix multi server builder resource page header

* deploy 2.3.0-dev-13

* fix builder resource header with multiple servers styling

* run dkf -> dku

* white background favicon + gen resources schema

* feat: break out cache/buffers and ZFS ARC from used memory (#1489)

* deploy 2.3.0-dev-14

* onmisearch improve finding containers / services

* refine service / container search

* deploy 2.3.0-dev-15

* deploy 2.3.0-dev-16

* bump mogh auth server, remove authors from cargo toml in line with newer spec

* deploy 2.3.0-dev-17

* improve selection of available building server, works when multiple builds sent simultaneously

* deploy 2.3.0-dev-18

* show stack services even when down

* improve stack services view when down

* deploy 2.3.0-dev-19

* mogh ui 0.7.0 including login page back button if already logged in

* deploy 2.3.0-dev-20

* fix containers pagination boundary

* fix update permissions on swarm

* deploy 2.3.0-dev-21

* skip alerting check on initial server cache refresh after startup

* deploy 2.3.0-dev-22

* Fix build - deployment flow when build doesn't publish semver image tags

* move check button to left of update available button

* omnisearch containers only fetch when query types

* Add cancel procedure / action apis

* add procedure / action cancel buttons

* deploy 2.3.0-dev-23

* Execution error

* useIsCancelling hook for better state conveyance

* fmt mem module

* allow all builders build to cancel during build

* deploy 2.3.0-dev-24

* bump rust to 1.96.1

* tweak ui index.html

* build webhook cancel build before triggering another - better behavior for back-to-back pushes

* deploy 2.3.0-dev-25

* De-vendor container apis from Docker

* deploy 2.3.0-dev-26

* startup support for pagination

* implement limit / page on the list routes

* swarm pagination and add swarm read support to cli

* use Option for limit

* resource selector and omni search using pagination / search

* deploy 2.3.0-dev-27

* update available disable action state polling in small

* resources page support pagination

* fix Image bug, improve resources page debounce

* fix omni missing !

* procedure failure update log provides link to view failed update

* fix omni search link ids with brute force query

* improve command error message formatting

* fix dashboard query for right resources

* attach linked resource names in addition to ids for efficient usage with pagination

* fix pagination bugs and improve pagination efficiency

* some brute force pagination fixes still with limit: 0

* deploy 2.3.0-dev-28

* replace limit: 0 server query with proper search based multi selector

* list api support filtering by state, use with dashboard active table

* Fix state filter pagination and create terminal limit: 0 queries

* deploy 2.3.0-dev-29

* deployment / stack filter by swarm id

* deploy 2.3.0-dev-30

* improve database query efficiency on large resource sets

* fix ListFull not filtering by query states

* fix the list permits respect resource.base_permission

* use saturating mul in skip computations

* Fix list all containers / stack services - tags query, terms case insensitive

* deploy 2.3.0-dev-31

* api based list resource sorting which works with pagination

* ui implement server side table sort

* fix cli usage

* deploy 2.3.0-dev-32

* ensure required refetch intervals are still passed for data freshness

* omni search services before containers

* add Deployment custom_name configuration to set specific container name

* GetResourceMatchingContainer fix empty container passed check

* validate conatiner / docker compatible names protect against injection

* track deployment deployed name for smooth swarm service renaming behavior

* deploy 2.3.0-dev-33

* batch executions support filtering by tag

* fix clippy lint

* improve tag multi selector matching resource sync config

* deploy 2.3.0-dev-34

* fix containers page networks / volumes wrapping

* use enum cmp for sorting by state

* container page uses api based sort

* move list stack methods

* deploy 2.3.0-dev-35

* stack / deployment state sorting prefers update available shown first

* ensure name is always fallback sort

* deploy 2.3.0-dev-36

* fix Source sorting for stacks, builds, syncs

* deploy 2.3.0-dev-37

* keepPreviousData method to prevent lots of loading flashes

* omni search tweaks / fixes

* fix clear on close

* paginated schedules

* for efficient schedule sort

* paginated terminals

* fix terminals cli

* fix clippy lint

* deploy 2.3.0-dev-38

* configurable default pagination, including 0 (no pagination)

* deploy 2.3.0-dev-39

* omnisearch use keepPreviousData

* Fix omni search auto highlight first item

* drop resource action guard / reset action state before pushing updates to clients for requery

* deploy 2.3.0-dev-40

* builder instance type use divided children

* default pagination limit 50

* UI: useDebouncedTermSearch hook

* stats page

* deploy 2.3.0-dev-41

* page description tweak

* dashboard tables show template query mode

* fix stats page legend over tooltip

* setup-periphery.py: add "--core-public-keys" command line argument (#1524)

* only log core public keys if provided

* fix terminal execute echo colliding with output sentinels (#1522)

Build the execute command as a single physical line so the PTY's local
echo cannot reproduce a bare sentinel line before the real output. The
`printf` format strings now use literal `\n` escapes (which printf
expands) instead of embedded newline bytes, keeping the emitted output
byte-identical while making the echoed command one line.

Closes #1289


Claude-Session: https://claude.ai/code/session_01M1ZTEJFKv3BAW36VmBwe2v

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* deploy 2.3.0-dev-42

* nowrap on server stats containers table

* improve Resources tabs with pagination support and multi select executions

* allow simultaneous server container execs

* Container page batch executions

* use controlled selection state for resources for proper clearing selection state after delete

* deploy 2.3.0-dev-43

* server docker resources multi select

* server docker tabs move execute button

* fix: log webhook branch-mismatch skips at debug instead of warn (#1528)

Git providers send push webhooks for every branch and Komodo filters
them server side (docs: Automate > Webhooks > Branch Filtering), so a
push to a non-matching branch is routine operation, not a failure. It
was surfaced through the generic 'Failed at running webhook' warn,
indistinguishable from genuine failures, and a repo with active bot
branches (e.g. Renovate) produces hundreds of these warns per day.

Rename ExtractBranch::verify_branch to branch_matches, returning
Ok(false) on a mismatch (logged at debug) so handlers skip quietly,
matching the existing silent webhook_enabled=false skip. Branch
EXTRACTION failures (e.g. a ref-less payload on a named-branch
listener) still return Err and reach the warn, preserving the
misconfiguration signal.

* fix: parse compose config before sanitizing so secret replacers cannot corrupt service detection (#1529)

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Maxwell Becker <49575486+mbecker20@users.noreply.github.com>

* clean up fix compose parse / sanitize ordering

* deploy 2.3.0-dev-44

* user permissioning fix search

* Fix GetHistoricalServerStats pagination

* server stats list (avoiding lots of queries) and server side sorting by stats (cpu, mem, disk)

* fix clippy lint

* deploy 2.3.0-dev-45

* fix ui build after monaco bump

* load average chart first in stats

* Fix deployment build version selector

* remove build version console log

* provide logical core count, update load to reflect

* deploy 2.3.0-dev-46

* add basic reporting functionality

* Add / fix shell escaping for periphery commands

* safe stdin token and prevent args passed through resource names on shell

* deploy 2.3.0-dev-47

* Delete only batch executions just use delete button

* add New / batch executions to dashboard tables

* rust 1.97.1

* deploy 2.3.0-dev-48

* default key reporting.key

* default reporting.key

* redeploy on build for all running unhealthy states (rebuild to fix eg restarting issue)

* resource updates query memo missing buildId in deps

* deploy 2.3.0-dev-49

* Fix reporting signature

* deploy 2.3.0-dev-50

---------

Co-authored-by: Remco Jongschaap <hey@dougley.com>
Co-authored-by: ChanningHe <52875777+ChanningHe@users.noreply.github.com>
Co-authored-by: Amos Shapira <amos.shapira@gmail.com>
Co-authored-by: Matt Van Horn <mvanhorn@users.noreply.github.com>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Christopher Plieger <917744+cplieger@users.noreply.github.com>
2026-07-29 15:08:28 -07:00

266 lines
7.3 KiB
Python

import argparse
import sys
import os
import shutil
import platform
import json
import urllib.request
def parse_args():
p = argparse.ArgumentParser(
prog="setup-periphery",
description="Install systemd-managed Komodo Periphery",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
p.add_argument(
"--version", "-v",
default=json.load(urllib.request.urlopen("https://api.github.com/repos/moghtech/komodo/releases/latest"))["tag_name"],
help="Install a specific Komodo version, like 'v2.0.0'"
)
p.add_argument(
"--user", "-u",
action="store_true",
help="Install systemd '--user' service"
)
p.add_argument(
"--root-directory", "-r",
default="/etc/komodo",
help="Specify a specific Periphery root directory."
)
p.add_argument(
"--core-address", "-c",
help="Specify the Komodo Core address for outbound connection. Leave blank to enable inbound connection server."
)
p.add_argument(
"--connect-as", "-n",
default=os.uname().nodename,
help="Specify the Server name to connect as. Defaults to hostname."
)
p.add_argument(
"--onboarding-key", "-k",
help="Give an onboarding key for automatic Server onboarding into Komodo Core."
)
p.add_argument(
"--force-service-file",
help="Recreate the systemd service file even if it already exists."
)
p.add_argument(
"--config-url",
default="https://raw.githubusercontent.com/moghtech/komodo/refs/heads/main/config/periphery.config.toml",
help="Use a custom config url."
)
p.add_argument(
"--binary-url",
default="https://github.com/moghtech/komodo/releases/download",
help="Use alternate binary source"
)
p.add_argument(
"--core-public-keys",
default="",
help="Trust Komodo Core public keys. Comma separated list of base58 encoded public keys."
)
return p.parse_args()
def load_paths(args):
home_dir = os.environ['HOME']
if args.user:
return [
# home_dir
home_dir,
# binary location
f'{home_dir}/.local/bin',
# config location
f'{home_dir}/.config/komodo',
# service file location
f'{home_dir}/.config/systemd/user',
]
else:
return [
# home_dir
home_dir,
# binary location
"/usr/local/bin",
# config location
"/etc/komodo",
# service file location
"/etc/systemd/system",
]
def download_binary(args, bin_dir):
# stop periphery in case its currently in use
user = ""
if args.user:
user = " --user"
os.popen(f'systemctl{user} stop periphery')
# ensure bin_dir exists
if not os.path.isdir(bin_dir):
os.makedirs(bin_dir)
# delete binary if it already exists
bin_path = f'{bin_dir}/periphery'
if os.path.isfile(bin_path):
os.remove(bin_path)
periphery_bin = "periphery-x86_64"
arch = platform.machine().lower()
if arch == "aarch64" or arch == "arm64":
print("aarch64 detected")
periphery_bin = "periphery-aarch64"
else:
print("using x86_64 binary")
# download the binary to bin path
if os.system(f'curl -f -sSL {args.binary_url}/{args.version}/{periphery_bin} -o {bin_path}') != 0:
raise RuntimeError(
f"Failed to download binary from "
f"{args.binary_url}/{args.version}/{periphery_bin}"
f"\n\nDid you provide a valid tag for '--version'? Check here for valid version tags:"
f"\nhttps://github.com/moghtech/komodo/tags"
)
# add executable permissions
os.popen(f'chmod +x {bin_path}')
def map_config_line(args, home_dir, line):
## Handle root directory
if line.startswith("root_directory ="):
if args.root_directory != None:
return f'root_directory = "{args.root_directory}"'
if args.user:
return f'root_directory = "{home_dir}/komodo"'
## Handle core_address
if line.startswith("# core_address =") and args.core_address != None:
return f'core_address = "{args.core_address}"'
## Handle connect_as
if line.startswith("# connect_as ="):
return f'connect_as = "{args.connect_as}"'
## Handle onboarding key
if line.startswith("# onboarding_key =") and args.onboarding_key != None:
return f'onboarding_key = "{args.onboarding_key}"'
## Handle core public keys
if line.startswith("# core_public_keys =") and args.core_public_keys:
return f'core_public_keys = "{args.core_public_keys}"'
return line
def write_config(args, home_dir, config_dir):
config_file = f'{config_dir}/periphery.config.toml'
# early return if config file already exists
if os.path.isfile(config_file):
print(f'Config at {config_file} already exists, skipping...')
return
print(f'creating config at {config_file}')
# ensure config dir exists
if not os.path.isdir(config_dir):
os.makedirs(config_dir)
template = urllib.request.urlopen(args.config_url).read().decode("utf-8").split("\n")
lines = [map_config_line(args, home_dir, line) for line in template]
config = "\n".join(lines)
with open(config_file, "w", encoding="utf-8", newline="\n") as f:
f.write(config)
def write_service_file(args, home_dir, bin_dir, config_dir, service_dir):
service_file = f'{service_dir}/periphery.service'
if args.force_service_file:
print("forcing service file recreation")
# early return is service file already exists
if os.path.isfile(service_file):
if args.force_service_file:
print("deleting existing service file")
os.remove(service_file)
else:
print(f'service file already exists at {service_file}, skipping...')
return
print(f'creating service file at {service_file}')
# ensure service_dir exists
if not os.path.isdir(service_dir):
os.makedirs(service_dir)
f = open(service_file, "x")
f.write((
"[Unit]\n"
"Description=Agent to connect with Komodo Core\n"
"\n"
"[Service]\n"
f'Environment="HOME={home_dir}"\n'
f'ExecStart=/bin/sh -lc "{bin_dir}/periphery --config-path {config_dir}/periphery.config.toml"\n'
"Restart=on-failure\n"
"TimeoutStartSec=0\n"
"\n"
"[Install]\n"
"WantedBy=default.target"
))
user = ""
if args.user:
user = " --user"
os.popen(f'systemctl{user} daemon-reload')
def uses_systemd():
# First check if systemctl is an available command, then check if systemd is the init system
return shutil.which("systemctl") is not None and os.path.exists("/run/systemd/system/")
def main():
args = parse_args()
print("=====================")
print(" PERIPHERY INSTALLER ")
print("=====================")
if not uses_systemd():
print("This installer requires systemd and systemd wasn't found. Exiting")
sys.exit(1)
[home_dir, bin_dir, config_dir, service_dir] = load_paths(args)
print(f'version: {args.version}')
print(f'core address: {args.core_address}')
if args.core_public_keys:
print(f'core public keys: {args.core_public_keys}')
print(f'connect as: {args.connect_as}')
print(f'user install: {args.user}')
print(f'home dir: {home_dir}')
print(f'bin dir: {bin_dir}')
print(f'config dir: {config_dir}')
print(f'service file dir: {service_dir}')
download_binary(args, bin_dir)
write_config(args, home_dir, config_dir)
write_service_file(args, home_dir, bin_dir, config_dir, service_dir)
user = ""
if args.user:
user = " --user"
print("Starting Periphery...")
print(os.popen(f'systemctl{user} start periphery').read())
print("Finished Periphery setup.\n")
print(f'Note. Use "systemctl{user} status periphery" to make sure Periphery is running')
print(f'Note. Use "systemctl{user} enable periphery" to have Periphery start on system boot')
if args.user:
print(f'Note. Use "sudo loginctl enable-linger $USER" to make sure Periphery keeps runnning after user logs out')
main()