small pixel drawing of a pufferfish zoa

checkpoint
Jes Olson j3s@c3f.net
Mon, 26 Sep 2022 21:59:08 -0500
commit

01466715825a6f3d3646aa8d5fe6c9a6aa238328

parent

7cc050285bee0f18cb7167158187b91a53945dda

4 files changed, 295 insertions(+), 49 deletions(-)

jump to
M READMEREADME

@@ -1,19 +1,81 @@

????????????????? - ? what is dis ? + ? what is zoa ? ????????????????? - zoa is the best config management tool ever. it's the - best because it's just written in posix shell & provides - a few nice little VERY USEFUL helpers, but doesn't go out + zoa is the best config management tool. it's the + best because it's the simplest. it's written in shell, has + a few nice little VERY USEFUL helpers, and doesn't go out of its way to make you hate yourself. - - it's also very opinionated about layout - there's generally - 1 correct way to do most common things. - + + zoa requires access to a git repo, though it may be used + in local development mode. + zoa is intended for human-scale deployment, and generally works best if you're not trying to manage a crazy complicated fleet of systems between multiple teams. zoa is for small, - tight-knit teams who want to keep it all in their heads. + tight-knit teams who want to keep it all in their heads with + minimal effort. + + it's also for individuals who like understanding their systems, + and hate maintaining them when things break for no reason. + + + + why did you write this? + + i manage systems with config management tools for a living. + i know how impossible they all are firsthand, i have 6+ years + of painful, painful experience. i wrote zoa to use on my personal +systems, because i hate the primary config management tools a lot. + + + + ~~ zoa doesn't pretend ~~ + + chef & ansible & puppet & salt all pretend to be + fully idempotent & declarative, but leave + actual declarative-ness and idempotence as + an exercise to the user. + + zoa doesn't pretend. zoa is not idempotent. zoa + is not declarative. it assumes your state changes + over time, and zoa makes it easy to track those + changes. you won't have to look at horrible docs + or commit a week to learning a god + damned + stupid + DSL + + other config management systems make their users + feel stupid. + + zoa doesn't. zoa uses shell scripts like every + single linux distro has used for millenia. it + has exactly zero dependencies besides zoa itself. + + zoa adheres to standards, and uses well-known + distro conventions. + + because it's easy. and simple. and honestly, + it's not very big. + + chef & ansible & puppet pretend that you can + work around bad packaging & applications + with config management! + + zoa doesn't! if a package is packaged poorly + or an application sucks to install, it will + equally suck in zoa. sorry. + + the other tools want to do a lot - search across + your nodes, deploy via their tooling, automate + testing, etc + + zoa is only concerned with _managing configuration_ + + and nothing else. forever. + + !!!!!!!!!!!!!!!!!! ! QUICKSTART !

@@ -21,67 +83,190 @@ !!!!!!!!!!!!!!!!!!

- ~ - understand: there are three components - ~ - - 1: the utility - 2: the language - 3: the layout + everything you need to know: + + 1: the utility + 2: env vars and helpers + 3: the layout --- 1: the utility --- - simply run the daemon on all of your systems. it's a simple binary (XXX: or - shell script?) that can be installed trivially. it wants to run as root, and - it should run on a cron schedule at whatever interval you want. + simply run the "zoa" tool on all of your systems. it's a simple binary (XXX: or + shell script?) that can be installed trivially. it expects to run as root, and + it should run on a cron/timer/whatever schedule at whatever interval you want. install: - wget -O https://j3s.sh/zoa + wget -O https://j3s.sh/zoa/zoa # TODO mv zoa /usr/local/sbin chmod +x /usr/local/sbin/zoa - in order to run zoa, you name a repo and a branch: - zoa https://git.cyberia.club/cyberia/layerze.ro.git main + design guideline: all configuration data comes from a git repository. + the nodes themselves keep no state at all. + + to run zoa: + zoa https://git.j3s.sh/config main + ^ ^ ^ + zoa, duh. git repo git ref (branch or tag) zoa will clone the repo+branch specified in your config (or attempt to fetch it, if it's already cloned) to /var/lib/zoa/<repo>/<branch> - when zoa runs, it sets a few env vars for your usage: - DISTRO="$(cat /etc/os-release | grep ^ID | cut -d = -f 2-)" + zoa will then execute /var/lib/zoa/<repo>/<branch>/main - then it simply executes. + if you run "zoa" with 0 arguments, it will execute if it finds exactly 1 + repo/branch combo in /var/lib/zoa - if you run zoa this way, it will not + clone the remote repo. this can be very useful for local testing. note + that the next run of zoa with a repo+branch will wipe any changes you + make in /var/lib. that's it, you've configured your server! set up a cronjob/systemd timer to run zoa on a schedule, if that's your thing. or just login and run it - periodically. you could even have the first run set up a cronjob that runs it + periodically. you could even have the first zoa run set up a cronjob that runs it + on a schedule, to make your life even easier. 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀 - --- 2: the language --- + + --- 2: environment variables and helper functions --- + + in zoa, you write plain POSIX shell. Why? + - posix shell is productive + - posix shell is portable + - posix shell is hard to make too complicated + + ENVIRONMENT VARIABLES + + before zoa runs, it sets a few standard environment variables for your usage. + here are _all of them_ on my dev machine: + OS="Linux" + DISTRO="arch" + NODENAME="nostromo.j3s.sh" + # design guideline: everything in zoa uses base units. MEM_TOTAL is in bytes. + MEM_TOTAL="16165548000" + + HELPER FUNCTIONS - basically, you can write plain shell, and there are some helpers for 90% of - what configuration management is about. + zoa has some little helper functions for common operations. - helpers: - # install package - pkg 'htop' - # place file - - # set permissions + zoa-file + usage: + zoa-file example.conf /etc/example.conf optional-command + ^ ^ ^ + source destination executed if the file changes + + description: + zoa-file takes a file from $zoa_root/files/ and places it on-disk + somewhere. if the file is changed, a command is optionally executed. + this can be very useful for things like reloading configurations. + + when you think about zoa-file, just think of it as regular cp, with an + extra argument for running arbitrary code if the cp does anything. + + examples: + zoa-file motd /etc/motd + zoa-file nginx/j3s.sh /etc/nginx/conf.d/j3s.sh systemctl reload nginx + + todo: + add a template processing step of some kind? + + zoa-script + usage: + zoa-script scriptname + ^ + script to execute + + description: + zoa-script executes the given script from $zoa_root/scripts/ + + examples: + zoa-script nginx + zoa-script 420/69 + --- 3: the layout --- - ah finally, how do i lay out my git repo? here's the canonical doc: + ah. finally. how do i lay out my zoa repo? - files/ - hosts/ - libs/ + here's the canonical fs layout: + main <-- entrypoint + files/ <-- arbitrary text files you'd like to place + scripts/ <-- arbitrary shell scripts - you need at least hosts/ - everything else is optional - hosts/ contains shell scripts that run on the host(s) specified - for example, - if i run zoa from domechild.cyberia.club, and this file is present: + you need at least main! everything else is optional. + + main is your entrypoint. if your whole vibe is just doing basic configuration + of nodes, you _could_ put literally everything in main and just be done with it. - hosts/domechild.cyberia.club + however, you may want main to be a little more complex: - then that is my entrypoint. + case $NODENAME in + git.j3s.sh) + . ./ + esac - libs/ contains functions and vars that can be defined for particular hosts, or - groups of hosts based on a special syntax + scripts/ contains arbitrary shell scripts. you can organize them how you'd like. files/ contains text files (no big files or binaries pls) that you might be - interested in placing on hosts. + interested in placing on hosts. these can be accessed with the zoa_file function. + + *~~~ warts ~~~* + * zoa doesn't support function definitions YET + * zoa reserved words must be all-on-one-line atm + + + + BONUS SECTION! :3 :3 <3 :3 + common config management patterns to zoa + +### install a package, +### but only if the distro is debian + + zoa +if [ "$DISTRO" = "debian" ]; then + apt install -y cowsay +fi + + ansible +- name: add package + when: ansible_facts['os_family'] == "Debian" + package: + name: 'cowsay' + state: present + +### place sshd_config, +### and reload ssh when it changes + ansible +# handlers/main.yml +- name: restart-sshd + service: + name: sshd + state: restarted + +# tasks/main.yml +- name: Configure sshd + template: + src: sshd_config.j2 + dest: /etc/ssh/sshd_config + owner: root + group: root + mode: 0644 + notify: restart-sshd + + zoa +zoa-file sshd /etc/ssh/sshd_config systemctl restart sshd +chown root:root /etc/ssh/sshd_config +chmod 0644 /etc/ssh/sshd_config + +### append an iptables rule to the input chain + ansible +- name: do the thing + iptables: + chain: INPUT + protocol: tcp + destination_port: '22' + ctstate: NEW + syn: match + jump: ACCEPT + + zoa +rule='INPUT --protocol tcp --dport 69 --jump ACCEPT' +iptables --check $rule || iptables --append $rule
M files/motdfiles/motd

@@ -1,1 +1,3 @@

hi this is a motd tbh + +welcome to my serb0r
M hosts/host.example.orgscripts/host.example.org

@@ -1,10 +1,7 @@

# install a file, set permissions, and update -# the apk repos if things have changed -# -# note that ZOA_FILES is available for use! -# $ZOA_FILES is equal to /var/lib/zoa/<repo>/<branch>/files/ +# the apk repos mkdir -p /etc/apk -cp "$ZOA_FILES/repositories" /etc/apk/repositories +cp "$zoa_root/files/repositories" /etc/apk/repositories chown root:root /etc/apk/repositories chmod 0644 /etc/apk/repositories apk update

@@ -16,6 +13,8 @@ # remember: file, owners, perms

# and optionally: a command to run if the file is updated zoa-file repositories /etc/apk/repositories root:root 0644 'apk update' + +zoa file -f repositories -o root -g root -m 0644 /etc/apk/repositories # zoa-file will only run "apk update" if the file is changed, or if its permissions # change. zoa-file also gives you more pretty output.

@@ -94,6 +93,6 @@ zoa-directory "/home/$operator/.ssh" "$operator:$operator" 0700

zoa-file "ssh_keys/$operator" "/home/$operator/.ssh/authorized_keys" "$operator:$operator" 0600 done -if [ -z "$make_backup_user" ]; then +if [ "$make_backup_user" = "true" ]; then useradd -S backup_user fi
A zoa

@@ -0,0 +1,60 @@

+#!/bin/sh +# +# zoa +# a simple posix config management system +# intended for human-scale usage + +# TODO: force shellcheck + +# funcs +# TODO: pretty print func + +die() { + printf "%s\n." "$1" + exit 1 +} + +# vars +# TODO: check for $1 $2 +# TODO: if zoa_repo == dev, skip git and use local dev mode +# TODO: check for bad chars in zoa_repo or zoa_branch +# TODO: make zoa_files lowercase everywhere +# TODO: if dev, make initial host file if it doesn't exist +# would "/" fuck us? etc +# aka validate input + +zoa_repo="$1" +zoa_branch="$2" +zoa_dev="$3" +if [ -n "$zoa_dev" ]; then + zoa_dir="./" + # skip the whole git clone & fetch +else + zoa_dir="/var/lib/zoa" +fi +zoa_workdir="$zoa_dir/$zoa_repo/$zoa_branch" +zoa_scripts="$zoa_workdir/scripts" +zoa_files="$zoa_workdir/files" +entrypoint="$zoa_workdir/hosts/$(uname -n)" + +# handle globhost? +if [ -f "$entrypoint" ]; then + exec "$zoa_workdir/hosts/$(uname -n)" +else + die "$entrypoint does not exist" +fi + +# check if repo exists locally +# true: +# check if git repo +# true: nothing +# false: exit +# check if branch is correct +# true: nothing +# false: exit +# fetch latest +# false: +# mkdir -p /var/lib/zoa/repos/ +# clone the repo to /var/lib/zoa/repo/branchname +# TODO: do we need branchname? +