-- Leo's gemini proxy

-- Connecting to perso.pw:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini;

(R)?ex automation for deploying Matrix synapse on OpenBSD


Author: Solène

Date: 31 May 2021

Tags: rex matrix openbsd


Comment on Mastodon


Introduction


Today I will introduce you to Rex, an automation tool written in Perl and using SSH, it's an alternative to Salt, Ansible or drist.


(R)?ex project website


Setup


You need to install Rex on the management system, this can be done using cpan or your package manager, on OpenBSD you can use "pkg_add p5-Rex" to install it. You will get an executable script named "rex".


To make things easier, we will use ssh from the management machine (your own computer) and a remote server, using your ssh key to access the root account (escalation with sudo is possible but will complicate things).


Get Rex


Simple steps


Create a text file named "Rexfile" in a directory, this will contain all the instructions and tasks available.


We will write in it that we want the features up to the syntax version 1.4 (latest at this time, doesn't change often), the default user to connect to remote host will be root and our servers group has only one address.


use Rex -feature => ['1.4'];

user "root";
group servers => "myremoteserver.com";

We can go further now.


Rex commands cheat sheet


Here are some commands, you don't need much to use Rex.


- rex -T : display the list of tasks defined in Rexfile

- rex -h : display help

- rex -d : when you need some debug

- rex -g <group> <task> : run a task on group


Installing Munin-master


An example I like is deploying Munin on a computer, it requires a cron and a package.


The following task will install a package and add a crontab entry for root.


desc "Munin-cron installation";
task "install_munin_cron", sub {
	pkg "munin-server", ensure => "present";

	cron add => "root", {
		ensure => "present",
		command = > "su -s /bin/sh _munin /usr/local/bin/munin-cron",
		on_change => sub {
			say "Munin cron modified";
		}
	};
};

Now, let's say we want to configure this munin cron by providing it a /etc/munin/munin.conf file that we have locally. This can be done by adding the following code:


	file "/etc/munin/munin.conf",
	source => "local_munin.conf",
	owner => "root",
	group => "wheel",
	mode => 644,
	on_change => sub {
		say "munin.conf has been modified";
	};

This will install the local file "local_munin.conf" into "/etc/munin/munin.conf" on the remote host, owned by root:wheel with a chmod 644.


Now you can try "rex -g servers install_munin_cron" to deploy.


Real world tasks


Configuring PF


This task deploys a local pf.conf file into /etc/pf.conf and reload the configuration on changes.


desc "Configuration PF";
task "prepare_pf", sub {

    file "/etc/pf.conf",
    source => "pf.conf",
    owner => "root",
    group => "wheel",
    mode => 400,
    on_change => sub {
        say "pf.conf modified";
        run "Restart pf", command => "pfctl -f /etc/pf.conf";
    };
};

Deploying Matrix Synapse


A task can call multiples tasks for bigger deployments. In this one, we have a "synapse_deploy" task that will run synapse_install() and then synapse_configure() and synapse_service() and finally prepare_pf() to ensure the rules are correct.


As synapse will generate a working config file, there are no reason to push one from the local system.


desc "Deploy synapse";
task "synapse_deploy", sub {
    synapse_install();
    synapse_configure();
    synapse_service();
    prepare_pf();
};

desc "Install synapse";
task "synapse_install", sub {
    pkg "synapse", ensure => "present";

    run "Init synapse",
    	command => 'su -s /bin/sh _synapse -c "/usr/local/bin/python3 -m synapse.app.homeserver -c /var/synapse/
    	cwd => "/tmp/",
    	only_if => is_file("/var/synapse/homeserver.yaml");
};

desc "Configure synapse";
task "synapse_configure", sub {
    file "/etc/nginx/sites-enabled/synapse.conf",
    	source => "nginx_synapse.conf",
    	owner => "root",
    	group => "wheel",
    	mode => "444",
    	on_change => sub {
    		service nginx => "reload";
    	};
};

desc "Service for synapse";
task "synapse_service", sub {
    service synapse => "ensure", "started";
};

Going further


Rex offers many feature because the configuration is real Perl code, you can make loops, conditions and extend Rex by writing local modules.


Instead of pushing configuration file from an hard coded local one, I could write a template of the configuration file and then use Rex to generate the configuration file on the fly by giving it the needed variables.


Rex has many functions to directly alter text files like "append-if_no_such_line" to add a line if it doesn't exist or replace/add/update a line matching a regex (can be handy to uncomment some lines).


Full list of Rex commands

Rex guides

Rex FAQ


Conclusion


Rex is a fantastic tool if you want to programmaticaly configure a system, it can even be used for your local machine to allow reproducible configuration or for keeping track of all the changes in one place.


I really like it because it's simple to work with, it's Perl code doing real things, it's easy to hack on it (I contributed to some changes and the process was easy) and it only requires a working ssh toward a server (and Perl on the remote host). While Salt stack also works "agent less", it's painfully slow compared to Rex.

-- Response ended

-- Page fetched on Thu Apr 25 00:20:02 2024