Applies a configuration described in YAML to the system. Distro-agnostic, cloud-init style, small scope, pluggable.
name: "Example"
stages:
default:
- name: "Write a file and run it"
files:
- path: /tmp/hello.sh
content: |
#!/bin/sh
echo "hello from yip"
permissions: 0755
commands:
- /tmp/hello.sh$> yip -s default file.yaml
$> yip -s default https://example.com/file.yaml
$> cat file.yaml | yip -- How it works
- CLI usage
- Cloud-init compatibility
- Node-data interpolation
- Stage filtering
- Configuration reference
Yip runs stages. A stage is a named list of steps, and each step is a map of fields that trigger built-in plugins. For example:
stages:
default:
- files:
- path: /tmp/bar
content: "hello"
permissions: 0644
commands:
- cat /tmp/barThe step above triggers two plugins in the same step: files (writes /tmp/bar) and commands (runs cat). Within a single step plugins run in a fixed order — you do not need to split them across steps to guarantee ordering.
A YAML file can define multiple stages, and yip can be told which one to run with -s <stage>. Multiple files can be passed on the command line; their stages are merged before execution.
If any step fails yip exits non-zero, but it keeps running the remaining steps and files.
yip loads cloud-init style yamls and applies them in the system.
For example:
$> yip -s initramfs https://<yip.yaml> /path/to/disk <definition.yaml> ...
$> yip -s initramfs <yip.yaml> <yip2.yaml> ...
$> cat def.yaml | yip -
Usage:
yip [flags]
Flags:
-e, --executor string Executor which applies the config (default "default")
-h, --help help for yip
-s, --stage string Stage to apply (default "default")
Sources can be local paths, HTTP(S) URLs, or - for stdin.
A subset of the official cloud-config spec is understood. If a file starts with #cloud-config it is parsed as cloud-init and mapped to the yip boot stage:
#cloud-config
users:
- name: "bar"
passwd: "foo"
groups: "users"
ssh_authorized_keys:
- faaapploo
ssh_authorized_keys:
- asdd
runcmd:
- foo
hostname: "bar"
write_files:
- encoding: b64
content: CiMgVGhpcyBmaWxlIGNvbnRyb2xzIHRoZSBzdGF0ZSBvZiBTRUxpbnV4
path: /foo/bar
permissions: "0644"
owner: "bar"Run with yip -s boot cloud-config.yaml.
Host data collected by sysinfo is exposed to templates in commands, files, and entity fields:
stages:
default:
- name: "echo hostname"
commands:
- echo "{{.Values.node.hostname}}"
name: "Test yip!"Each step supports a set of predicates that decide whether it runs. Predicates are AND-ed: all of them must pass for the step to execute.
Evaluates the expression as a shell command. The step runs only when the command exits 0.
stages:
default:
- name: "debug boot only"
if: "cat /proc/cmdline | grep debug"
commands:
- echo "debug enabled"Runs (or skips) the step based on file existence. Accepts three optional sub-lists:
any: at least one of the files exists.all: all of the files exist.none: none of the files exist.
Combine them freely — the step runs when every provided sub-condition is satisfied.
stages:
default:
- name: "only on Linux hosts that never saw yip"
if_files:
any:
- /etc/os-release
all:
- /etc/passwd
none:
- /var/lib/yip/done
commands:
- touch /var/lib/yip/doneRuns the step only on hosts whose hostname matches the pattern. Accepts a Go regexp.
stages:
default:
- node: "bastion.*"
commands:
- echo "runs on bastion hosts only"Matches the ID and VERSION_ID fields from /etc/os-release. Both are compiled as Go regexps.
stages:
default:
- name: "ubuntu or opensuse-leap"
only_os: "ubuntu|opensuse-leap"
commands:
- echo hello
- name: "everything but ubuntu"
only_os: "^(?!ubuntu).*"
commands:
- echo hello
- name: "ubuntu 20.04 or 22.04"
only_os: "ubuntu"
only_os_version: "20.04|22.04"
commands:
- echo helloMatches runtime.GOARCH (amd64, arm64, riscv64, ...) against a Go regexp.
stages:
default:
- name: "only on arm64"
only_arch: "arm64"
commands:
- echo "arm64!"
- name: "arm64 or amd64"
only_arch: "arm64|amd64"
commands:
- echo helloRuns the step only when the host uses the given service manager. Supported values: systemd, openrc. Detection is done by probing for the corresponding binaries; a system where both are present is treated as ambiguous and the step is skipped.
stages:
default:
- name: "enable service under systemd only"
only_service_manager: "systemd"
systemctl:
enable:
- my-serviceBelow is a reference of all keys available in a step.
Human-readable description of the step. Used only when printing progress to the console.
stages:
default:
- name: "Setup logging"
commands:
- echo "started"Declares that this step depends on other named steps. Yip uses this to build a dependency graph within a stage. The referenced names must match the name field of other steps in the same stage.
stages:
default:
- name: "write config"
files:
- path: /etc/myapp.conf
content: "key=value"
- name: "start service"
after:
- name: "write config"
commands:
- systemctl start myappCreates directories on disk. Runs before files so that file writes into fresh directories succeed in one step.
stages:
default:
- name: "Setup folders"
directories:
- path: "/etc/foo"
permissions: 0600
owner: 0
group: 0Writes files to disk.
Supported encoding values: b64, base64, gz, gzip, gz+base64, gzip+base64, gz+b64, gzip+b64. Owner and group can be given as numeric uid/gid (owner, group) or as a string (ownerstring: "user:group" or "user").
stages:
default:
- files:
- path: /tmp/bar
content: |
#!/bin/sh
echo "test"
permissions: 0755
owner: 1000
group: 100
- path: /etc/motd
encoding: b64
content: SGVsbG8gd29ybGQK
ownerstring: "root:root"Downloads files over HTTP(S) and writes them to disk. timeout is in seconds; 0 means no timeout.
stages:
default:
- downloads:
- path: /usr/local/bin/tool
url: "https://example.com/tool"
timeout: 30
permissions: 0755
ownerstring: "root:root"Clones a git repository into path. Supports HTTPS with username/password and SSH with a private key. branch_only: true fetches only the specified branch (single-branch checkout).
stages:
default:
- name: "Clone config repo"
git:
url: "https://github.com/example/config.git"
path: /opt/config
branch: "main"
branch_only: true
auth:
username: "gituser"
password: "gitpassword"
- name: "Clone via SSH key"
git:
url: "git@github.com:example/private.git"
path: /opt/private
branch: "main"
auth:
private_key: |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
# optional; set to true to skip host key verification
insecure: trueAdds or modifies users. Each entry is keyed by username and takes the following fields. Every field is optional and of type string unless noted otherwise. When a user already exists, only the password is updated.
- name: Login name. Defaults to the map key.
- passwd: Password hash. Plain strings are accepted as well.
- gecos: GECOS comment.
- homedir: Home directory. Defaults to
/home/<name>. - no_create_home: Boolean. Skip home directory creation.
- primary_group: Primary group name. Defaults to a new group named after the user.
- groups: List of additional groups the user belongs to.
- no_user_group: Boolean. Skip creating the per-user primary group.
- ssh_authorized_keys: List of public SSH keys to add for this user. Entries in
github:<name>/gitlab:<name>form are resolved by fetching the user's public keys from the corresponding service. - system: Boolean. Create a system account (no home directory).
- no_log_init: Boolean. Skip initializing lastlog and faillog.
- shell: Login shell.
- lock_passwd: Boolean. Lock the account password (equivalent to setting
!in/etc/shadow). - uid: Numeric user id. When set, the user is created with this exact uid — no free-uid search and no home-directory-owner reuse. Useful on immutable systems where
/etc/passwdis regenerated on every boot but/homeis persisted, to keep file ownership stable. - gid: Numeric group id for the user's own primary group. When set (and
primary_groupis empty), the primary group is created with this exact gid. Ifprimary_groupis set too, that group's existing gid is used andgidis ignored.
stages:
default:
- name: "Setup users"
users:
bastion:
passwd: "strongpassword"
homedir: "/home/bastion"
shell: "/bin/bash"
groups:
- wheel
ssh_authorized_keys:
- github:mudler
svc-app:
uid: "12345"
system: true
shell: "/usr/sbin/nologin"Adds SSH keys to the authorized_keys file of an existing user. Entries starting with github: or gitlab: are fetched from those services.
stages:
default:
- name: "Provision SSH keys"
authorized_keys:
mudler:
- github:mudler
- "ssh-rsa AAAA..."
root:
- "ssh-ed25519 AAAA..."Adds a user or group in the entities format. Useful when you need full control over the /etc/passwd, /etc/shadow, or /etc/group row.
stages:
default:
- name: "Ensure system user"
ensure_entities:
- path: /etc/passwd
entity: |
kind: "user"
username: "foo"
password: "x"
uid: 1500
gid: 1500
info: "Foo service user"
homedir: "/home/foo"
shell: "/bin/bash"Removes a user or group entity from the system.
stages:
default:
- name: "Drop legacy user"
delete_entities:
- path: /etc/passwd
entity: |
kind: "user"
username: "legacy"Sets the machine hostname on the running system, writes it to /etc/hostname, and updates /etc/hosts.
stages:
default:
- hostname: "node-01"Writes /etc/resolv.conf (or the file specified in path).
stages:
default:
- name: "Setup DNS"
dns:
nameservers:
- 8.8.8.8
- 1.1.1.1
search:
- example.com
options:
- "timeout:2"
path: "/etc/resolv.conf"Sets kernel parameters via /proc/sys/<key>, equivalent to sysctl -w.
stages:
default:
- name: "Kernel tuning"
sysctl:
net.ipv4.ip_forward: "1"
debug.exception-trace: "0"Loads kernel modules.
stages:
default:
- name: "GPU driver"
modules:
- nvidia
- nvidia_uvmWrites variables to /etc/environment (or the file specified in environment_file).
stages:
default:
- environment:
FOO: "bar"
HTTP_PROXY: "http://proxy:3128"Overrides the file written by environment. Use it to target a user-specific env file such as ~/.envrc instead of the system-wide /etc/environment.
stages:
default:
- environment_file: "/home/user/.envrc"
environment:
FOO: "bar"Writes a drop-in file at /etc/systemd/timesyncd.conf.d/10-yip.conf (under the [Time] section). Any key from timesyncd.conf can be set.
stages:
default:
- name: "Setup NTP"
systemctl:
enable:
- systemd-timesyncd
timesyncd:
NTP: "0.pool.ntp.org 1.pool.ntp.org"
FallbackNTP: ""Runs systemd-firstboot with the given map. Keys map to --<key>=<value> arguments (keymap, locale, timezone, ...).
stages:
default:
- systemd_firstboot:
keymap: us
locale: en_US.UTF-8
timezone: Europe/MadridManages systemd unit state and optionally drops override files. All lists are optional.
- enable: units to enable.
- disable: units to disable.
- start: units to start now.
- mask: units to mask.
- overrides: list of drop-in override files. Each entry:
- service: unit name (
.serviceis appended if missing). Required. - name: override file name. Optional, defaults to
override-yip.conf..confis appended if missing. - content: full content of the override file.
- service: unit name (
Overrides are written even if the unit is not enabled or does not exist yet.
stages:
default:
- name: "Configure services"
systemctl:
enable:
- systemd-timesyncd
- cronie
mask:
- purge-kernels
disable:
- crond
start:
- cronie
overrides:
- service: "systemd-timesyncd"
name: "override-custom.conf"
content: |
[Service]
ExecStart=
ExecStart=/usr/lib/systemd/systemd-timesyncdInstalls, removes, refreshes, or upgrades packages using the host package manager. The distro is detected from /etc/os-release; supported managers: apt-get (Debian/Ubuntu), dnf (Fedora/RHEL/Rocky/Alma/Oracle/CentOS/openEuler), zypper (openSUSE/SLE), pacman (Arch), apk (Alpine).
Operation order is: refresh → upgrade → install → remove.
stages:
default:
- name: "Base packages"
packages:
refresh: true
upgrade: false
install:
- vim
- curl
remove:
- nanoBest-effort version pinning applied before package installs. The exact mechanism depends on the detected package manager:
- apt-get: writes
/etc/apt/preferences.d/99-yip-pinswithPin-Priority: 1001. - dnf: writes
/etc/dnf/plugins/versionlock.conf+ aversionlock.list. Full NEVRA is resolved withdnf repoquerywhen possible, otherwise a raw pattern is used. - zypper: runs
zypper addlock name=version, falling back toaddlock nameif the version-scoped lock is rejected. - apk: rewrites
/etc/apk/worldwithname=versionentries. - pacman: not supported; the step is skipped with a warning.
stages:
default:
- name: "Pin kernel and container runtime"
package_pins:
linux-image-generic: "5.15.0-91.101"
containerd.io: "1.7.11"Repartitions a disk: adds partitions in the trailing free space and/or expands the last partition. Sizes are always in MiB; size: 0 means "use all remaining free space".
Device targeting: the target disk is picked by matching (in order) label (filesystem or partition label) or path. path also accepts a script://<command> form — the command is executed and its trimmed stdout is used as the device path, useful when the target is not known ahead of time.
If init_disk: true the disk is wiped and a fresh GPT is written. Destructive — only use on a disk you fully control. disk_name (optional) makes the GPT GUID deterministic (UUIDv5 derived from the name under the URL namespace, uuid.NamespaceURL).
Only the last partition can be expanded, and expansion happens before any new partition is added. Expansion only grows the partition — it never shrinks it.
For add_partitions:
- size (required): MiB.
0means all remaining free space. - fsLabel: filesystem label. Optional.
- pLabel: partition label. Optional but recommended — if a partition with the same
pLabelalready exists it is left untouched, otherwise data may be lost. - filesystem:
ext2(default),ext3,ext4,fat,vfat,fat16,fat32,xfs,btrfs,swap, ornoformat/-/noneto create the partition without formatting. - bootable: boolean. Sets the bootable flag and the corresponding partition GUID type.
stages:
default:
- name: "Repart disk"
layout:
device:
label: COS_RECOVERY
path: /dev/sda
init_disk: true
disk_name: "MYDISK"
expand_partition:
size: 4096 # 0 for all remaining free space
add_partitions:
- fsLabel: COS_STATE
size: 8192
pLabel: state
- fsLabel: COS_PERSISTENT
filesystem: ext4
size: 0
- fsLabel: COS_GRUB
size: 512
filesystem: fat32
bootable: true
- pLabel: raw_data
size: 1024
filesystem: noformatUnpacks OCI images onto the filesystem. platform is optional and defaults to the host platform.
stages:
default:
- name: "Unpack images"
unpack_images:
- source: "quay.io/luet/base:latest"
target: "/usr/local/luet/"
- source: "rancher/k3s:latest"
target: "/usr/local/k3s-arm64"
platform: "linux/arm64"Fetches user data from the specified cloud providers. The list is iterated in order and the first provider that succeeds is used. Provider-specific data is written under /run/config; user data is stored at path.
stages:
default:
- name: "Fetch cloud user data"
datasource:
providers:
- "aws"
- "digitalocean"
path: "/etc/cloud-data"Runs arbitrary shell commands. Executes after file/directory writes so newly written files and directories are available.
stages:
default:
- name: "Regenerate initrd"
commands:
- dracut -f
- depmod -a