Units

A Unit is a shell script which invokes various hooks that Sysunit will call throughout a run. These are, in order of their execution:

  • meta: Provides metadata about the unit, such as its name, description, and parameters that it accepts.
  • deps: Lists the units that this unit depends on.
  • check: Determines if the unit needs to be applied or removed
  • apply: Applies the unit to the system
  • remove: Removes the unit from the system

Let's start with a basic example and go from there. Here's a simple unit that puts the current time into a file.

# foo_file.sh

apply() {
    echo "Writing the current date to /tmp/foo"
    date > /tmp/foo;
}

Running sysunit apply foo_file.sh will run the apply hook, which will write the current date to /tmp/foo.

Note that the output from your unit is captured when doing this, and is only displayed if the unit fails to help you diagnose issues.

You can increase the verbosity of Sysunit with the --verbose flag to always include this output, which can be helpful for monitoring the progress of units that will take a long time to execute. Just like in a shell script, output from commands executed in your unit will also be included, so if you invoke a package manager for example, you can see what it's doing while your unit executes with this method.

Note

Sysunit is only intended to handle printable characters! Outputting arbitrary binary can cause issues with its handling of output, and may cause your unit to fail.

See How It Works for more information on why this is the case.

Idempotency

The unit above is not idempotent, so Sysunit will run it every time you call sysunit apply foo_file.sh. To make it idempotent, you can add a check hook. Let's also provide a remove hook so sysunit can remove the file.

# foo_file.sh

check() {
    if [ -f /tmp/foo ]; then
        echo "Found /tmp/foo"
        present
    else
        echo "Did not find /tmp/foo"
    fi
}

apply() {
    echo "Writing the current date to /tmp/foo"
    date > /tmp/foo;
}

remove() {
    echo "Removing /tmp/foo"
    rm /tmp/foo;
}

Now when you run sysunit apply foo_file.sh, Sysunit will check if /tmp/foo exists, and if it does, it will not run the apply hook. If you run sysunit remove foo_file.sh, it will remove /tmp/foo, only if it already exists.

Handling Errors

Sysunit runs unit hooks in a shell with set -e -u, meaning that any non-zero exit status from your commands will cause the unit to fail, and any output to be printed to aid with diagnosis of the issue. Let's look at a unit that will fail:

# fail.sh

apply() {
    echo "I have chosen not to comply"
    false
}

On running this, you should see output to the terminal telling you which unit failed, and include its output.

If the output is not enough to go off of, you can invoke sysunit with --debug which will include trace output from your script (this is just set -x in the subshell that your unit runs in.)