aconfmgr

repository·master·Indexed 23 days ago

https://github.com/cybershadow/aconfmgr

A configuration manager for Arch Linux designed to track, manage, and restore system configurations. It uses shell scripts to describe the desired state of installed packages and /etc/ configuration files, featuring 'save' and 'apply' subcommands to synchronize the system state with configuration files.

Tokens
3.2K
Snippets
8
Records
15
Agent score
32%

What's inside aconfmgr

  1. Understand how aconfmgr differs from other configuration managers

    master

    aconfmgr is a local-only configuration manager for Arch Linux with several key distinctions from other tools:

    • vs. Puppet/Ansible: Unlike these tools which manage systems via remote agents or background services, aconfmgr manages only the local system. While Puppet/Ansible manage only what is explicitly defined in a config file, aconfmgr manages the entire system; if an item is absent from the configuration file, it is considered absent from the system. aconfmgr also features a save command to transcribe the current system state into a configuration file.
    • vs. NixOS: Like NixOS, aconfmgr uses a text file to describe the system state. However, aconfmgr does not forbid direct file edits under its control. It provides a mechanism to transcribe manual changes back into the configuration to maintain idempotency.
    • vs. lostfiles: aconfmgr provides a superset of lostfiles functionality, including the ability to save exclusions to a configuration file.
    • vs. etckeeper: While etckeeper manages /etc in version control, aconfmgr allows for similar versioning but requires manual handling for merging configuration files with upstream package versions (which can be achieved via inlining file changes).
  2. How aconfmgr works: save vs apply

    master

    The aconfmgr tool operates using two primary subcommands that are mutually idempotent (running them twice in a row results in no changes):

    • aconfmgr save: Calculates the difference between the current system state and the configuration described in your directory. It writes these differences to 99-unsorted.sh as shell commands. This is used to capture new changes made to the system.
    • aconfmgr apply: Calculates the difference between your configuration directory and the current system state. It then applies those changes by installing/removing packages and creating/editing configuration files to match your scripts.

    Internal Mechanism: The tool evaluates your shell scripts to 'compile' a system description in an output directory. It then compares this compiled description against the actual system state to determine necessary actions.

  3. How aconfmgr manages packages

    master

    On Arch Linux, aconfmgr focuses on explicitly-installed packages. It ignores hard dependencies to avoid cluttering your configuration.

    Package Lifecycle Rules:

    • Tracking: aconfmgr save only saves packages marked as explicitly installed.
    • Pruning: Packages that are neither explicitly listed in your configuration nor hard dependencies of other installed packages are considered 'orphans' and will be removed during aconfmgr apply.
    • Optional Dependencies: If a package is only an optional dependency of another, it must be explicitly listed in your configuration, otherwise aconfmgr apply will prune it.
    • Enforcement: When aconfmgr apply runs, it sets the install reason of packages listed in your configuration to 'explicitly installed'. To remove unlisted packages, it first unpins them (sets them to 'installed as a dependency') and then prunes orphans.
  4. Inline file content and edits

    master

    Instead of copying entire files into the files/ directory, you can inline content directly into your configuration using bash heredocs or echo. This is useful for small files or single-line changes.

    To modify an existing file from a package without copying the whole thing, use GetPackageOriginalFile to extract the original version, then use standard tools like cat, sed, or augtool (Augeas) to apply edits to that extracted file.

    # Inlining entirely
    echo "kernel.sysrq = 1" > "$(CreateFile /etc/sysctl.d/99-sysrq.conf)"
    
    # Appending to an original package file
    cat >> "$(GetPackageOriginalFile systemd /etc/systemd/system.conf)" <<EOF
    RuntimeWatchdogSec=10min
    ShutdownWatchdogSec=10min
    DefaultTimeoutStartSec=30s
    DefaultTimeoutStopSec=30s
    EOF
    
    # Using Augeas for structured edits
    GetPackageOriginalFile filesystem /etc/resolv.conf > /dev/null
    aug set '/files/etc/resolv.conf/nameserver[101]' 127.0.0.1
  5. Perform a first run to capture system configuration

    master

    To transcribe your current system's configuration into the configuration directory, run aconfmgr save.

    By default, the configuration directory is ~/.config/aconfmgr, or ./config if running directly from a git clone. You can override this location using the -c flag.

    Workflow for a clean first run:

    1. Run aconfmgr save to generate 99-unsorted.sh and other configuration files.
    2. If you see unwanted temporary or auto-generated files, create an ignore file (e.g., 10-ignores.sh) in the configuration directory using IgnorePath commands (see Ignoring files).
    3. Delete everything in the configuration directory except your ignore file and re-run aconfmgr save.
    4. Review 99-unsorted.sh and sort its contents into organized, numbered shell scripts (e.g., 10-base.sh, 20-drivers.sh) using bash syntax.
    5. Delete 99-unsorted.sh once you have moved all desired configurations into your sorted files.
    6. Run aconfmgr apply to synchronize the system state with your new configuration (this will remove any packages or files not included in your sorted scripts).
  6. Manage multiple systems with one configuration

    master

    You can use a single configuration repository to manage multiple similar machines by using shell logic (like if statements checking $HOSTNAME) to conditionally add packages or files.

    For large or binary files that shouldn't be inlined, use CopyFileTo to map different source files to the same destination based on the hostname.

    # Conditional package installation
    if [[ "$HOSTNAME" == "home.example.com" ]]
    then
    	AddPackage nvidia
    	AddPackage nvidia-utils
    fi
    
    # Conditional file inlining
    f="$(GetPackageOriginalFile filesystem /etc/hosts)"
    echo '1.2.3.4 home.example.net' >> "$f"
    if [[ "$HOSTNAME" == "laptop.example.net" ]]
    then
    	echo '127.0.1.1 laptop.example.net laptop' >> "$f"
    fi
    
    # Using CopyFileTo for different machine-specific files
    CopyFileTo "/etc/hosts-$HOSTNAME" "/etc/hosts"
  7. Install aconfmgr

    master

    You can install aconfmgr by cloning or downloading the GitHub repository. The tool will automatically install any necessary dependencies during execution. Alternatively, an AUR package is available for easier management on Arch Linux.

    https://aur.archlinux.org/packages/aconfmgr-git/
  8. Maintain and version your configuration

    master

    The configuration directory should be managed with a version control system like Git.

    Best Practices:

    • Version your scripts: Commit your sorted .sh configuration files.
    • Ignore 99-unsorted.sh: This file should not be versioned. Its presence indicates that the current system state has changed in a way that is not yet reflected in your configuration scripts.
    • Periodic Maintenance: Regularly run aconfmgr save. If it produces changes (like a new 99-unsorted.sh), review those changes, sort them into your configuration files, document them, and commit them.
  9. Restore or set up a system using a configuration

    master
    To restore an existing system or configure a new one, ensure your desired configuration files are present in the configuration directory, then run aconfmgr apply. The tool will provide a preview of changes and ask for confirmation before applying them to the system.
    aconfmgr apply
  10. Filter file contents to ignore specific parts

    master

    If a file contains frequently changing values (like timestamps) that you want to ignore, you can use a content filter.

    1. Define a bash function that takes the filename as the first parameter, reads the file contents from stdin, and writes the filtered contents to stdout.
    2. Register the filter using AddFileContentFilter PATTERN FUNCTION.

    Note: Only one function can be configured per unique pattern. The most recently added rule takes precedence.

    function NetworkManagerConnectionFilter() {
    	grep -v '^timestamp='
    }
    
    AddFileContentFilter '/etc/NetworkManager/system-connections/*.nmconnection' NetworkManagerConnectionFilter
  11. Compare system state with configuration using diff

    master

    You can use the diff action to see the differences between the current system state and the configuration you have defined. This shows what changes aconfmgr apply would make.

    The diff direction is from system to configuration.

    • If a file is part of a package and unmodified on the system, it compares the original package version to your configuration.
    • If a file is absent from your configuration, it compares the filesystem version to the original package version.
    $ aconfmgr --skip-config --skip-inspection diff /etc/resolv.conf
  12. Known limitations of aconfmgr

    master

    When using aconfmgr, be aware of the following current limitations:

    • Ambiguous Dependencies: Dependencies where multiple packages provide the same functionality (e.g., fcron and cronie both providing cron) are not tracked. You must pin or add these dependencies to your configuration manually.
    • AUR Virtual Packages: Installing AUR packages that depend on virtual packages (e.g., java-environment) is not currently supported. To resolve this, you can manually specify the desired dependency in your configuration or use a supported AUR helper.