small pixel drawing of a pufferfish zoa

README

                ?????????????????
                ?  what is zoa  ?
                ?????????????????

  zoa is a simple, opinionated, shell-based config management tool.
        it's the best. it's pull-based.

  zoa makes you feel good about config management.

  zoa config lives in a git repo, and all of the systems you manage
  simply point at the repo.

  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 with
  minimal effort.

  it's also for individuals who like understanding their systems,
  and hate maintaining them when things break for no reason.

  you might like zoa if:
  - you enjoy alpine, gentoo, linux from scratch, etc
  - you use a tiling window manager
  - you like messing with dotfiles
  - you dislike chef, ansible, saltstack, and puppet intensely
  - you like smallness and simplicity
  - you think nix just seems way too god-damned complicated

  you might not like zoa if:
  - you are an abstraction enjoyer
  - you dislike shell, the language
  - you dislike the terminal in general



     -> quickstart

     # install zoa
        $ wget https://j3s.sh/zoa/zoa (TODO)
        $ mv zoa /usr/local/sbin
        $ chmod +x /usr/local/sbin/zoa
     # set up your zoa repo with an entrypoint
        $ mkdir zoa
        $ cd zoa
        $ printf 'uname -a' > main
     # push your zoa repo
        $ git init
        $ git add --all
        $ git commit -m 'my first zoa commit weee'
        $ git remote add origin git@your-git-repo
        $ git push
     # finally, as root:
        $ zoa git@your-git-repo

       done.
       you have set up config management for your host. read on for
       more deets! :3



              why did you write this? (are you insane)

  first, yes, duh, but also:
       i manage systems with config management tools for a living. (6+ years)
     i know how impossible they all are to operate & keep up with
  years of painful, painful experience. i wrote zoa to use on my personal
systems, because i hate the main config management tools a lot. 

               also, i <3 shell :D



             ~~ 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 keep up with those
      changes. you won't have to look at horrible doc websites
      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.

      zoa is easy. and simple. and honestly,
      quite a smol guy

    the other tools want to do a lot - search across
    your nodes, deploy via their tooling, automate
    testing, manage AWS resources?!?!?  

      zoa is only concerned with _managing configuration_

      _on servers_

      and nothing else. forever.

    the other tools break constantly because they
    try to do everything.

      zoa breaks rarely because it does almost nothing.

    other tools are slow because they have HUGE runtimes and scopes

      zoa is comparatively fast, because it's just running god dang
      shell scripts :3
      zoa doesn't require:
      - ssh
      - python
      - ruby
      - a chef server or salt master

    other tools abstract too much

      zoa abstracts a few definitely useful functions, but
      otherwise gets out of the way and gives you a light
      framework to speak shell to your systems.

      in zoa, you write plain POSIX shell. Why?
      - posix shell is productive!
      - posix shell is portable!
      - posix shell is the language of system configuration!
      - posix shell is easy to remember!
      - posix shell rarely changes!



          zoa's design touchstones
          ------------------------
          * no config on the nodes
            node-side config is cumbersome. everything
            should be adjustable via git and git alone.
          * expose 1 way to do common things
            zoa exposes only 1 hostname var, only 1 copy function,
            has 0 flags, and 1 way to run via git, and 1 way to 
            format your repository. less overhead for you.
          * adopt functionality slowly
            zoa is starting with a minimal set of built-in functions
            because i only want to maintain functions in order to address
            severe pain-points. most things should just be handled via shell.
          * as standards-compliant as reasonable
            but not ball-breakingly so tbh, see $HOSTNAME for an example
            of zoa not being "fully" standards compliant.



               !!!!!!!!!!!!!!!!!
               !    DETAILS    !
               !!!!!!!!!!!!!!!!!

  - ~ - understand: there are three components - ~ -

          everything you need to know:

                1: the utility
                2: env vars and helpers
                3: the layout

         --- 1: the utility ---

  zoa is a single binary.

  it expects to run as root (it is managing your system, after all),
  and it should probably run on a cron/timer/whatever schedule at
  whatever interval you want.

  installation process:
    wget https://j3s.sh/zoa/zoa # TODO
    mv zoa /usr/local/sbin
    chmod +x /usr/local/sbin/zoa

  to run zoa:
    zoa https://git.j3s.sh/j3s/config main
    ^              ^                   ^
  zoa, duh.       git repo             optional git branch

  zoa will clone the repo+branch specified to /var/lib/zoa/repo, and then
  it will execute the "main" script in that repo - more on that later.

  to run zoa in local-only mode:
    zoa /path/to/zoa/dir
  
  in which case, zoa will just execute main from that dir you specify

  that's it, you've run zoa! now set up a cronjob/systemd timer to
  run zoa on a schedule, if that's your thing. or just login and run zoa
  periodically.

         👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀
  you could even have the first zoa run set up a cronjob that runs zoa
  on a schedule, to make your life even easier.
         👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀


         --- 2: environment variables and helper functions ---

                        ENVIRONMENT VARIABLES

  before zoa runs, it sets a few standard environment variables for your usage.
  here are _all of them_.

    displayed values are from my dev system
    caveats are marked with *

    $PATH - the search path for binaries. this is hardcoded.
      PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

    $ARCH - the name of the hardware type on which the system is running
      ARCH=x86_64

    $HOSTNAME - the name of this node.
      HOSTNAME=nostromo.j3s.sh
        * there is no shortname vs fqdn standard, so this env var may vary
          by distro

    $OS - the operating system name
      OS=Linux
        * on BSD systems, this var is a lot more useful
        * if you want your distro, take a look at OS_RELEASE_ID

    $RELEASE - the current release level of the operating system implementation
      RELEASE=5.19.5-arch1-1
  
       ! WARNING: ALL $OS_RELEASE_* VARIABLES ARE UNRELIABLE !
            be sure to check for their existence before
            using them. ty~ :3

    $OS_RELEASE_ID - short uncapitalized name of your distro
      OS_RELEASE_ID=arch
        * see above warning

    $OS_RELEASE_VERSION_ID - version of your distro, if applicable
      OS_RELEASE_VERSION_ID=  # note that arch has no version ID
        * see above warning

    TODO: expose hardware info, cpu cores, ip address, memory availability, etc


                          HELPER FUNCTIONS

     zoa has some little helper functions for common operations.

    * 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 /var/lib/zoa/scripts/
          this is basically shorthand for ". /var/lib/zoa/repo/script/scriptname",
          and also adds some nice decorators.

        examples:
          zoa-script nginx
          zoa-script 420/69


         --- 3: the layout ---

  ah. finally. how do i lay out my zoa repo?

  here's the canonical repo layout:

         main     <-- file, entrypoint
         files/   <-- dir, contains arbitrary text files
         scripts/ <-- dir, contains arbitrary shell scripts

  you need at least main. everything else is optional.

  main is your entrypoint. you could just stick everything in main and
  be done with it, if you want.

  however, if you want main to be a little more capable,
  here's one starting point:

      case $HOSTNAME in
          git.j3s.sh)
              # note that the CERTS env var will
              # pass into any scripts called after
              # it is defined, as if they're all 1
              # long script
              CERTS='git.j3s.sh'
              zoa-script certs
              zoa-script git
          ;;
          j3s.sh)
              CERTS='j3s.sh'
              zoa-script certs
              zoa-script web
          ;;
      esac

  scripts/ contains arbitrary shell scripts. you can organize them
  how you'd like. dirs are supported.

  files/ contains text files (no big files or binaries) that you might be
  interested in placing on hosts. these can be accessed with the zoa-file function.


               wat is borked?
      - branch cloning doesn't work rn idk why
      - the cloned git repo has root perms & git hates that
      - the repo is re-cloned on every run *shrug*


                  BONUS SECTION! :3 :3 <3 :3
          common config management patterns in zoa

### define a reusable function
in zoa, this is easy - just define a shell
function:
die() {
  printf "%s.\n" "$1"
  exit 1
}

every sub-script that is called will automatically
have access to it. env vars work the same way.

### install a package

(this is distro dependent)
apt update
apt install -y cowsay

### install a package, but only if the distro is debian

if [ "$OS_RELEASE_ID" = "debian" ]; then
  apt install -y cowsay
fi
  
### place sshd_config, set permissions, and reload ssh when it changes

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

rule='INPUT --protocol tcp --dport 69 --jump ACCEPT'
iptables --check $rule || iptables --append $rule

### clone a remote git repo, pull it constantly

git clone git@git.sr.ht:~example/example /opt/repo ||
  git fetch /opt/repo