Dirk's Tech Findings

csync2: Workaround to be able to pull files

Publication date: 2020-05-05

Issue: csync2 can only push changed files to the target

The target cannot pull. But sometimes it is desirable to request changes to be sent, e.g. when the target device has been down when push was attempted.

Note that in my scenario, the source is the master, the target a read-only slave. This looks as follows (both on source as well as the target) in the csync2 config:

group mygroup
{
    host masterhost;
    host (slavehost);
    key /etc/csync2/key_mygroup;
    include /etc/myapp/mygroup/*;
}

The source can push the files in the directory "/etc/myapp/mygroup/" to the target. Of course, csync2 needs to be listening on the target.

The target cannot push files to the source since it is configured as slave (denoted by the brackets around "slavehost"). Any attempts to do so fail. Note that a very verbose output ("-vvv") needs to be selected to get a cleartext explanation why it fails.

The target cannot pull files from the source, i.e. request any pending changes be sent from source to target on target request.

Solution: Use "action" statement to enable a pull initated on the target

We can implement a workaround that enables such a pull of pending changes with existing csync2 capabilities.

We let the target create a marker file like "/etc/myapp/mygroup/target_wants_to_pull_changes" in the directory to be mirrored. When the target tries to push the changes to the source, this fails as described above. However, we can make use of the fact that an action statement on the source for this file is nevertheless triggered for execution.

Thus - only on the source side - we add an action statement that calls csync2 on the source to mirror the changes to the target.

group mygroup
{
    host masterhost;
    host (slavehost);
    key /etc/csync2/key_mygroup;
    include /etc/myapp/mygroup/*;

{% if grains.id.partition('.')[0]=="masterhost" %}
    action
    {
        pattern /etc/myapp/mygroup/target_wants_to_pull_changes;
        exec "csync2 -xv >> /var/log/csync2_push_after_pull_request.output";
        logfile "/var/log/csync2_push_after_pull_request.log";
    }
{% endif %}

}

In the configuration above you can see Jinja2 code that can be used when provisioning the config file with Saltstack. With the condition statement, the same config file can be used for both source and target when using Saltstack (in this case, the action statement won't be part of the config file on target side).

With this, csync2 needs to be listening on both source and target. When the target wan't to request changed files on the source to be sent to the target, it just needs to create the file "/etc/myapp/mygroup/target_wants_to_pull_changes" and initate csync2 (e.g. using "csync2 -xv"). This won't mirror that flag file since the target is just a slave. But it will trigger the action on the master that runs "csync2 -xv" that pushed any pending changes from source to target. The file "/etc/myapp/mygroup/target_wants_to_pull_changes" will be deleted on the target in this process.

Back to topic list...