An easy solution for system/dotfile configuration
Loosely based off of Ansible for the task and file organization
pip3 install instaterUsing yay:
yay -Sy instaterUsing makepkg:
git clone https://aur.archlinux.org/instater.git
cd instater
makepkg -sircSee the File Structure Example below to set up variables, files, and tasks.
Once a setup.yml file is created, it can be run using
instater
# or:
instater --setup-file setup.ymlTo see what changed will be made, but not actually make then, use --dry-run:
instater --dry-runFor a complete example, see dotfiles
First, create a setup.yml file:
# Lots of ways to prompt for data at the beginning of execution
vars_prompt:
- name: my_var
- name: custom_prompt
prompt: Enter something here
- name: private_var
private: true
- name: private_confirm_var
private: true
confirm: true
- name: allow_empty_var
allow_empty: true
# variables that can be used within tasks/files can be populated
# from a static file, in this case vars/common.yml
vars_files:
- vars/common.yml
# variables can be used within the file names
- "vars/{{ vars_file }}.yml"
# All of the tasks to perform are enumerated
tasks:
- name: Copy file
# {{ username }} is replaced with the variable `username`
copy:
content: "The contents of a new file in here"
dest: "/home/{{ username }}/Downloads/file1"
mode: "600"
# if desired, the output of this task can be registered to use as
# a condition for subsequent tasks
register: file1_copy
- name: Run a command if file1 written
command: "touch /home/{{ username }}/testfile"
when: file1_copy.changedThen, create a vars/ directory and common.yml within:
my_test: 1
some_var: "{{ my_test + 2 }}"
vars_file: "second"
username: somethingAnd vars/second.yml (since common.yml set vars_file to second):
from_second_yml: data in hereNow in all of the tasks, my_test, username, from_second_yml, etc will be
present and accessible.
All tasks support the following arguments:
name(string, optional): The name of the task, included in logswhen(string, optional): A Jinja2 statement to determine whether the task should be skipped. If the statement evaluates toTrue, the task will be executed. Example:my_variable == 'foo'register(string, optional): A variable to store task results under. Can be used in conjunction with a subsequentwhenclause, for exampleregister: my_taskcan be used in another task aswhen: my_task.changedwith_fileglob(string, optional): If provided, find all files in the instater root that match the glob, and create a task with all other
Example of register and when:
- name: Set locale to en_US
copy:
content: "en_US.UTF-8 UTF-8\n"
dest: /etc/locale.gen
register: locale_gen
- name: Generate locale files
command: locale-gen
when: locale_gen.changedExample of with_fileglob:
- include: "{{ task }}"
with_fileglob: "applications/*"Install packages from a Arch User Repository
packages(string, [string]): The packages to install, can be a single package or a list of packagesbecome(string, optional): A user to become while installing packages
Examples:
- name: Install python package
aur:
packages: python
become: makepkg
- name: Install python libraries
aur:
packages:
- python-setuptools
- python-wheelRun arbitrary shell commands (can be risky)
command(string, [string]): The command or commands to executecondition(string, optional): A command to run prior to thecommand, as a condition for whether or not it should actually be executedcondition_code(int, optional): The return code from theconditioncommand to match against. If theconditionreturns this code, thecommandwill be executed. Defaults to 0become(string, optional): A user to become while running the commands (including the condition command)directory(string, optional): The working directory to use while running the commands
Note that the command and conditions may make use of pipes, for example
curl -s https://get.sdkman.io | bash
Examples:
- name: Make a curl
command:
command: curl https://google.com
- name: Create a file if it doesn't exist
command:
command: touch to/file
condition: ls to/file
condition_code: 2
directory: path
- name: Run several commands
command:
command:
- echo "This does nothing"
- echo "More commands"Copy a file, directory, url, or direct string content to a destination file or directory
dest(string): The destination file or directory to write tosrc(string, optional): The source file or directory to copycontent(string, optional): The exact content that should be copied to the desturl(string, optional): A url to GET and use as the contentowner(string, optional): The owner to set on the file. Note that if a parent directory must be created, it may not be given this owner and should be created separatelygroup(string, optional): The group to set on the file. Note that if a parent directory must be created, it may not be given this group and should be created separatelymode(string, integer, optional): The file permissions to set on the destination. Note that if a YAML integer is provided, it must start with a0to be parsed as octalis_template(bool, optional): If set to true, the content will be rendered using Jinja2 and all available variables before comparing or writing todestvalidate(string, optional): A command to run to validate the source file or content prior to writing it to the destination. Should contain a%swhich will be replaced by a filename to validate. When applied to a directory, each file is separately validated
Exactly one of src, content, or url must be provided
Examples:
- name: Copy a file
copy:
src: files/my_file.txt
dest: /path/to/destination
- name: Copy a directory
copy:
src: files/my_directory
dest: /path/to/dest
- name: Copy and set owner/group/mode
copy:
src: files/executable.sh
dest: /usr/local/bin/executable.sh
owner: some_user
group: some_group
mode: 0755
- name: Download a url
copy:
url: https://raw.githubusercontent.com/nayaverdier/instater/main/README.md
dest: /path/to/instater/README.md
owner: my_user
group: my_user
- name: Copy content directly
copy:
content: "{{ hostname }}"
dest: /etc/hostname
- name: Copy and validate sudoers file
copy:
src: files/sudoers
dest: /etc/sudoers
mode: 0440
validate: /usr/sbin/visudo -csf %s
- name: Render jinja template and copy
copy:
src: files/my_template
dest: /path/to/file
is_template: trueLog a debug message
debug(str): The message to log
- name: Log execution information
debug: "Instater root directory: {{ instater_dir }}"Create a directory. Same as passing directory: true to the file task.
(see file)
- name: Create example directory
directory:
path: "/path/to/directory"
- name: Create a user directory
directory:
path: "/home/exampleuser/private_directory"
owner: exampleuser
group: exampleuser
mode: 0700Create an empty file, directory, symlink, or hard link on the file system.
path(string): The path of the file or directory to managetarget(string, optional): When managing asymlinkorhard_link, the target file or directory to point toowner(string, optional): The owner to set on the file. Note that if a parent directory must be created, it may not be given this owner and should be created separatelygroup(string, optional): The group to set on the file. Note that if a parent directory must be created, it may not be given this group and should be created separatelymode(string, integer, optional): The file permissions to set on the destination. Note that if a YAML integer is provided, it must start with a0to be parsed as octaldirectory(boolean, optional): If set totrue, create a directorysymlink(boolean, optional): If set totrue, create a symlinkhard_link(boolean, optional): If set totrue, create a hard link
At most one of directory, symlink, and hard_link may be provided
- name: Create an empty file
file:
path: /path/to/file
- name: Create an empty file with owner/group/mode
file:
path: /home/myuser/myfile
owner: myuser
group: myuser
mode: 0600
- name: Create a symlink
file:
path: /etc/localtime
target: /usr/share/zoneinfo/America/New_York
symlink: true
- name: Create a hard link
file:
path: /path/to/new/file
target: /path/to/existing/file
hard_link: true
- name: Create a directory
file:
path: /path/to/my/dir/
directory: true
- name: Create a directory with owner/group/mode
file:
path: /home/myuser/dir/
owner: myuser
group: myuser
mode: 0700
directory: trueClone or update a git repository
repo(string): The git repo uri to clonedest(string): The destination path to clone intodepth(integer, optional): Creates a shallow clone with truncated historyfetch_tags(boolean, optional): Whether or not to fetch git tags (defaults to true)become(string, optional): The UNIX user that should be used to run git commands
- name: Clone instater
git:
repo: https://github.com/nayaverdier/instater
dest: /home/myuser/Documents/instater
become: myuser
- name: Clone with truncated history
git:
repo: https://github.com/nayaverdier/instater
dest: /home/myuser/Documents/instater
depth: 1
become: myuserCreate a UNIX group
group(string): The name of the UNIX group to create
- name: Create a group
group: mygroupCreate a hard link to a file
(see file)
- name: Create a hard link
hard_link:
path: /path/to/new/linked/file
target: /path/to/existing/fileInclude another YAML file containing tasks, to allow for better organization of tasks
include(string): The path of the YAML file to include (relative to the setup.yml)
- include: tasks/something.yml
- include: "{{ item }}"
with_fileglob: "tasks/applications/*"Install Arch Linux packages using the pacman, yay, or makepkg commands
packages(string, [string]): The packages to install, can be a single package or a list of packagesaur(boolean, optional): If set to true, the packages will be installed from the Arch User Repository usingyay(ormakepkgas a fallback)become(string, optional): Whenauris true, install using a specific user
Examples:
- name: Install python package
pacman:
packages: python
- name: Install python libraries
pacman:
packages:
- python-setuptools
- python-wheel
- name: Install instater
pacman:
packages:
- instater
aur: true
become: makepkgStart, enable, or disable a systemctl service
service(string): The name of the service to managestarted(boolean, optional): If set totrue, start the serviceenabled(boolean, optional): Whether or not the service should be enabled
- name: Enable postgres service
service:
service: postgresql
started: true
enabled: true
- name: Start redis service
service:
service: redis
started: trueCreate a symlink to a file or directory
(see file)
- name: Create a symlink
symlink:
path: /path/to/new/linked/file
target: /path/to/existing/fileCopy data, transforming the content as a Jinja2 template prior to writing.
Same as passing is_template: true to copy
(see copy)
- name: Copy configuration template
template:
src: files/some_config
dest: "/home/{{ username }}/.config/some_config"
owner: "{{ username }}"
group: "{{ username }}"
mode: 0644Create a UNIX user
user(string): The name of the user to createsystem(boolean, optional): Whether or not this user is a system user (only used when the user needs to be created)create_home(boolean, optional): Whether or not a home directory for this user should be createdpassword(string, optional): A hashed password to set as the user's password (only used when the user needs to be created )shell(string, optional): The login shell to use for the usergroups(string, [string]): The group or groups to add the user to
- name: Create primary user
user:
user: my_username
shell: /usr/bin/zsh
groups: sudo
password: "{{ login_password | password_hash('sha512') }}"
when: login_password is defined
- name: Create makepkg user
user:
user: makepkg
groups: makepkg
system: true