resticprofile icon indicating copy to clipboard operation
resticprofile copied to clipboard

[Discussion] Regarding systemd units (includes feature requests/ideas)

Open Syphdias opened this issue 3 years ago • 6 comments

Hi, I started writing my own restic wrapping for running restic via systemd. After that I found resticprofile. I am currently in the process of replacing my systemd units with resticprofile ones but ran into some questions. I don't mean this as "hey you should do things differently and my way is the right way" but I do have some suggestions and hope you don't mind.

For my use case: I use 2 restic repos ("s3" and "local") on my machine and backup / and $HOME in different intervals. I also do regular restic forgets and restic prunes for both repositories.

Legend: I use "job" for "backup", "check", "forget" and "prune". Not sure what it is actually called I am trying to avoid "command".

timers and units

By default a timer called [email protected] or baz.timer will activate [email protected] or baz.service respectively. You define it explicitly with Unit= which is not necessary unless you activate a service which has another name. I haven't see this anywhere with resticprofile, yet. This also works with instances of templates (see below).

activating/scheduling

Currently there is no --dry-run option for resticprofile schedule and resticprofile unschedule as far as I can tell. And it seems to be impossible to only activate certain jobs (e.g. backup) but not others (check) without adjusting config. Also I'd like to be able to create the unit files, but not activate them right away (symlinking to timers.target.wants directory) but only creating the service and timer units. (More of a feature request than a discussion)

systemd templating

I noticed you use the systemd template syntax but you don't utilize it. What I mean by that is that you use template@instance (for timer or service) but you create a file for each of them. An example how this could be done with a template (only including important parts, this not an actual unit):

# /etc/systemd/system/[email protected]
[Service]
ExecStart=/usr/local/bin/resticprofile --no-prio --no-ansi --config /etc/resticprofile/profiles.toml --name %i check

This has the benefit of uncoupling the scheduling and activating from resticprofile. You could still use the resticprofile schedule but you would only need one template for each job (backup, check, etc.). This also means you can activate jobs for profiles that have no schedule without additional config needed.

timer templating

The same concept works for timers but not as well because there are three things to take into account: profile, job and schedule. In my version I opted for one timer per job and schedule combination, meaning [email protected] would run [email protected] every month (notice different names in the units). If I wanted I could also activate [email protected] with no additional unit files and it would activate [email protected] every month.

For resticprofile you have one file per schedule-job-profile and the naming is a bit different. So I think it is hard to improve with different schedules. You could combine job and schedule, but I don't think it would be very useful. Example: You'd need a name of a schedule, here monthly and create a timer for a job, e.g. [email protected]. You could then activate it [email protected] to run [email protected]. If you wanted to change the schedule. You'd need a new timer.

Not sure if possible but ~the~ my dream would be to have something like one timer for each schedule that can then activate a combination of job and profile. Timer: [email protected] Activate [email protected] to run [email protected] every month. There is no nice way to do this.

But if there way a way to call resticprofile in a way that told it profile and job in one sting it would be possible and would even reduce more unit files. The proposal would be as follows:

resticprofile s3.check (resticprofile <profile>.<job>) would behave the same as resticprofile --name s3 check This means the service unit template can look like this:

# /etc/systemd/system/[email protected]
[Service]
ExecStart=/usr/local/bin/resticprofile --no-prio --no-ansi --config /etc/resticprofile/profiles.toml %i

To do the check, start [email protected] (i.e. resticprofile@<profile>.<job>.service). For timers you'd still need one unit per unique schedule, e.g. [email protected], [email protected], etc. You can then easily activate different schedules for different profiles and times like so:

If you totally hate the systemd unit structure I propose here. I still would love to have the feature to use resticprofile <profile>.<job>. Then I could build the systemd parts on my own.

I saw #27, and wonder what @jkellerer thinks of that ideas above.

Syphdias avatar Jun 26 '21 14:06 Syphdias

By default a timer called [email protected] or baz.timer will activate [email protected] or baz.service respectively. You define it explicitly with Unit= which is not necessary unless you activate a service which has another name. I haven't see this anywhere with resticprofile, yet.

That's true, I forgot about that. Although it doesn't hurt to be precise 😛

Currently there is no --dry-run option for resticprofile schedule and resticprofile unschedule as far as I can tell. And it seems to be impossible to only activate certain jobs (e.g. backup) but not others (check) without adjusting config.

I suppose we could add a flag for specifying the jobs we want to schedule (defaults to all)

Also I'd like to be able to create the unit files, but not activate them right away (symlinking to timers.target.wants directory) but only creating the service and timer units. (More of a feature request than a discussion)

Sure, can do 😄

I noticed you use the systemd template syntax but you don't utilize it. What I mean by that is that you use template@instance (for timer or service) but you create a file for each of them.

This is not as easy as it sounds:

  • I still need to create one template per config file (it might not be a real case scenario to use more than one config file but I need it for my tests)
  • The command line is not static: depending on the target some parameters can be added (--log, --lock-wait or --no-lock). This is because running a job directly from the command line or from a schedule can be slightly different.

I don't mind changing the unit structure, but we need to find a way to pass more parameters to the command in the service file, if it's possible

I still would love to have the feature to use resticprofile <profile>.<job>. Then I could build the systemd parts on my own.

Can do as well. But just for an easy parsing of the command line I might do something more like resticprofile --run <profile>.<job> if you don't mind

creativeprojects avatar Jun 26 '21 19:06 creativeprojects

This is not as easy as it sounds:

Yeah, I kinda expected a catch :wink:

  • The command line is not static: depending on the target some parameters can be added (--log, --lock-wait or --no-lock). This is because running a job directly from the command line or from a schedule can be slightly different.

Is that something that needs to be in the ExecStart=? It sounds like it could be both read from the config file and the overridden by command line arguments if needed. I assume you need read access to the same config file anyways. Side node: I noticed --no-ansi but it looks like you already check if you have a tty (tested with | cat) and remove color (and maybe more). Possibly not necessary – not sure if you clean up restic output here – or could be added "smartly" unless forced.

  • I still need to create one template per config file (it might not be a real case scenario to use more than one config file but I need it for my tests)

I don't use them but user scope units might be another issue as well where you need multiple units.

I don't mind changing the unit structure, but we need to find a way to pass more parameters to the command in the service file, if it's possible

Well, the --run <profile>.<job> would be a way to pass two arguments via instance but what do you mean exactly? I see two ways to pass parameters to services at the moment: @instance and through the config file (and maybe the environment/scope it is run in). I guess if you wanted you could define config files to be included/imported for different jobs but as you mentioned the amount of real case scenarios might be quite small.

Syphdias avatar Jun 27 '21 15:06 Syphdias

The additional flags specific to a schedule are in the config file indeed, starting with schedule- so yes, it is technically possible just to put one flag on the command line telling to read the additional flags from the schedule configuration.

So we could potentially have one template per user per config file

creativeprojects avatar Jun 28 '21 10:06 creativeprojects

FYI: I slapped together a proof of concept for --run and will try it in the next days and hopefully won't break my backups. It's just shoddily piggybacking on your code since I can't write golang. (It's just another language. but I can hardly distinguish between = and :=).

Syphdias avatar Jun 30 '21 10:06 Syphdias

Cool 👍🏻

You know, that exactly how I started with Go. And now it's my favourite programming language 😄

creativeprojects avatar Jun 30 '21 10:06 creativeprojects

Works great so far. Trying to figure out how to backup via stdin now.

Syphdias avatar Jul 05 '21 17:07 Syphdias