Gentoo Archives: gentoo-amd64

From: Duncan <1i5t5.duncan@×××.net>
To: gentoo-amd64@l.g.o
Subject: [gentoo-amd64] Re: Systemd migration: opinion and questions
Date: Mon, 02 Mar 2015 05:13:40
Message-Id: pan$70c01$55eb964a$c41ab754$d017dd2a@cox.net
In Reply to: Re: [gentoo-amd64] Systemd migration: opinion and questions by Rich Freeman
1 Rich Freeman posted on Sun, 01 Mar 2015 14:13:53 -0500 as excerpted:
2
3 > On Sun, Mar 1, 2015 at 1:20 PM, Marc Joliet <marcec@×××.de> wrote:
4 >>
5 >> Regardless: thoughts?
6 >
7 > I'd probably just do this:
8 >> Am Sun, 1 Mar 2015 08:34:19 -0500 schrieb Rich Freeman
9 >> <rich0@g.o>:
10 >>>
11 >>> The timer keeps running if you set the dependency on the service. So,
12 >>> next time the timer runs, it will try again. You might want to just
13 >>> set an hourly job and have it check for a successful run in the last
14 >>> day or whatever.
15 >>>
16 > You could of course trigger this from either the mount or hourly.
17 > Anytime you mount the drive or every hour systemd will run the service,
18 > and the service will see if it managed to do a backup/etc in the last
19 > day/week/whatever, and then run if appropriate.
20
21 This is actually how I setup several former cron-jobs as systemd timers,
22 here, based on an hourly check somewhat similar to what most crons
23 (including gentoo's for over 10 years now and mandrake's before that) are
24 actually setup to do to get around the fact that cron won't on-its-own
25 trigger after restart if the machine was down or cron not running when
26 the configured time for a job ran.
27
28 Here's how I have it setup here. Note that my initials are jed, and I
29 use them regularly as a prefix/suffix to denote custom configs (here,
30 systemd units) I've created myself, as opposed to those shipped in
31 whatever package.
32
33
34 /etc/systemd/system/jed.hourly.timer:
35
36 [Unit]
37 Description=JED Hourly timer
38
39 [Timer]
40 OnBootSec=10min
41 OnUnitActiveSec=1h
42 Unit=jed.hourly.target
43
44 [Install]
45 WantedBy=timers.target
46
47
48 timers.target is a systemd default target with the purpose of starting
49 all the various timers. The install entry says to install a symlink
50 pointing to jed.hourly.timer in the timers.target.wants subdir, which
51 will of course cause timers.target to start it.
52
53 The 10 minute OnBootSec setting says wait 10 minutes after boot before
54 activating this timer the first time. The 1h OnUnitActiveSec setting
55 says reactivate it every hour after its first activation. Thus, we have
56 an hourly timer, except that its first run is offset from boot by only 10
57 minutes, not a full hour.
58
59 Meanwhile, what it actually does when it runs is activate
60 jed.hourly.target -- that's the Unit= line.
61
62
63 /etc/systemd/system/jed.hourly.target:
64
65 [Unit]
66 Description=JED Hourly target
67 StopWhenUnneeded=yes
68
69
70 This one, like most targets, is pretty simple, its only purpose being a
71 synchronization point, activating a bunch of services and/or other units,
72 generally those with symlinks installed in the corresponding
73 jed.hourly.target.wants subdir, at once.
74
75 Note the StopWhenUnneeded=yes setting. The sole purpose of activating
76 this thing is to trigger all its wants deps to run, and as soon as it has
77 done that, it can stop again. This lets the target "rest" between hourly
78 triggerings.
79
80
81 Symlinks in /etc/systemd/jed.hourly.target.wants/:
82
83 jed.hourly.timestamp.service
84
85
86 That's it, just the one. With just it there it would have in fact been
87 just as easy for me to set jed.hourly.timer's
88 Unit=jed.hourly.timestamp.service, and omitted jed.hourly.target
89 entirely. However, using the target is MUCH more flexible, as it allows
90 me to add new services I want triggered hourly to the same target, as I
91 decide I want/need them.
92
93 If you're familiar with the usual cron setup, in particular, the usual
94 /etc/crond.hourly/ (or whatever it was, that's from memory as I replaced
95 my cronjobs with timers and don't even have a cron installed, these
96 days), that's EXACTLY the function /etc/systemd/jed.hourly.target.wants
97 ends up filling, with the minor exception being that as I set it up, it
98 triggers hourly, starting 10 minutes after boot, instead of hourly, at
99 some arbitrary minute of the hour. That actually suits my purposes
100 better than an arbitrary time of the hour would, but if people really
101 wanted more-cron-line specific minutes of the hour, that would be set
102 using OnCalendar= instead of the boot+10min and hourly thereafter, that I
103 used.
104
105
106 /etc/systemd/jed.hourly.timestamp.service:
107
108 [Unit]
109 Description=JED Hourly timestamp updater
110
111 [Service]
112 Type=oneshot
113 ExecStart=/etc/systemd/local-scripts/jed.hourly.timestamp
114
115 [Install]
116 WantedBy=jed.hourly.target
117
118
119 This service simply runs the script named in execstart, oneshot, meaning
120 it runs until its done, then stops. Which is what we want, since we're
121 triggering it once per hour via the timers above.
122
123 The install section simply tells systemd where to put that symlink
124 mentioned above, in the appropriate target.wants subdir, when the service
125 is "installed".
126
127
128 /etc/systemd/local-scripts/jed.hourly.timestamp:
129
130 #!/bin/bash
131
132 stampfile=/var/log/jed.hourly.day.stamp
133
134 # if stamp is old or doesn't exist, update stampfile and run...
135 doit(){
136 touch $stampfile
137 systemctl start jed.daily.target
138 exit
139 }
140
141 [[ -f stampfile ]] || doit
142
143 yesterday=$(date -d yesterday +"%Y%m%d%H%M")
144
145 stamp=$(date -r "$stampfile" +"%Y%m%d%H%M")
146
147 [[ $stamp ]] || doit
148
149 [[ $stamp -lt $yesterday ]] && doit
150
151 exit 0
152
153
154 This is where the custom magic happens and the real work gets done. If
155 you're familiar with the usual cronjob runscripts setup, this will look
156 similar. Basically, systemd timers, etc, magic above only sets up an
157 hourly systemd timer, not a daily, weekly, etc. This script actually
158 sets up a daily trigger, based on a daily timestamp that's checked every
159 hour to see if it has been 24 hours or longer since the last run, updated
160 if so, and the daily trigger triggered.
161
162 As I said, the idea is very similar to that used with a standard cronjob
163 runscripts setup, since that's exactly where I got it from. =:^) Like
164 the cronjob setup, if the system was down the hour the daily would have
165 otherwise triggered, this script ensures that it's triggered the next
166 time the hourly timer is run... which will normally be 10 minutes after
167 boot due to the 24 hours elapsing when the system was down, and the boot
168 +10min setting in that first unit, jed.hourly.timer, above.
169
170 OK, so what does this script trigger? systemctl start jed.daily.target
171
172 Again, I /could/ have setup a daily timer much like the hourly timer, and
173 handled it that way. Instead, I chose to use the hourly time to activate
174 a service to run this script, handling the daily mechanism that way.
175
176 (FWIW I put the stampfile itself in /var/log primarily because that's a
177 conveniently writable place to put it. My /, including much of /var, is
178 mounted read-only by default, while /var/log obviously must be writable.
179 And thought about from a particular viewpoint, that timestamp /is/ a log
180 in some fashion, since it effectively logs the last time the daily jobs
181 should have run.)
182
183 OK, we're almost there now. =:^) But tying up loose ends...
184
185
186 /etc/systemd/system/jed.daily.target:
187
188 [Unit]
189 Description=JED Daily Target
190 StopWhenUnneeded=yes
191
192
193 Pretty much identical to the hourly target as the functionality is the
194 same, just with a different name, reflecting the different timing.
195
196
197 Symlinks in /etc/systemd/system/jed.daily.target.wants:
198
199 jed.daily.logrotate.service.
200
201
202 For the moment that's it. I haven't needed weekly, monthly, etc,
203 scheduling, so I've not created it. But having done the hourly to daily
204 thing, I could easily copy and convert that to weekly or whatever,
205 triggered by the daily, just as daily is triggered by the hourly.
206
207 And to tie up the final loose end before I apply the above to the case of
208 this thread, as well as to supply a sample logrotate systemd service for
209 anyone else wanting to switch to systemd timer based triggering and get
210 rid of cron's triggering (while noting that the systemd way to do it
211 would be to use tmpfiles.d settings, but I still find logrotate useful
212 for doing actual log rotation, thus keeping those settings separate from
213 systemd's config)...
214
215
216 /etc/systemd/system/jed.daily.logrotate.service:
217
218 [Unit]
219 Description=JED daily logrotate
220
221 [Service]
222 Type=oneshot
223 Nice=10
224 ExecStart=/usr/sbin/logrotate --state /var/log/logrotate.state /etc/
225 logrotate.conf
226
227 [Install]
228 WantedBy=jed.daily.target
229
230
231 (Note the wrap of the execstart line...)
232
233 ###################
234
235 OK, so how does all that apply to the case of this thread? =:^)
236
237 Simple enough. Where I threw in that jed.hourly.timestamp.service systemd
238 unit file (that is, symlinked into the hourly target.wants subdir) and
239 jed.hourly.timestamp script that it called, you'd throw in another
240 service, either in addition to the timestamp one I used, or if you don't
241 want to use my daily solution, in place of it.
242
243
244 The key thing to understand here is that once you've setup a service to
245 run a script you create yourself, you can have it do literally whatever
246 you want it too, just as you would with any other script -- it's NO
247 LONGER limited to the strict declarative style and options systemd
248 provides -- you're ONLY using systemd to /start/ it. =:^)
249
250 So... suppose you want it to check hourly to see if it can and should
251 trigger something else, but only run once a day... the timer and
252 timestamp-script-based framework I have above already does the hourly
253 check part, as well as the only running once a day part.
254
255 If you prefer that it check every 10 minutes, it's simple enough to
256 change that hourly thing to 10 minutes. If you like it hourly but want
257 it to ALWAYS be hourly, including not checking the first time until an
258 hour after boot, that's simple enough as well. Similarly, if you want
259 the final action to run only every two days, or twice a day, or
260 whatever. It's simple enough to change the timestamp mechanism to make
261 that happen.
262
263 Meanwhile, with the basic framework already there, it should also be
264 simple enough to plugin some conditional logic testing to see if the
265 partition device-files are showing up or not. If not, simply quit
266 without updating the timestamp and wait for the next hourly or whatever
267 check to roll around. If so, and the timestamp is also expired, then run
268 the scripted backup or whatever else you were wanting it to do.
269
270 ... And of course you can rename them from jed.* to your own name of
271 choice, too. Jed.* is fine for my own usage, but it would look a bit
272 ridiculous, and could well defeat its site-specific-id purpose if someone
273 actually decided to ship it as part of some package, if that jed.* naming
274 pattern remained as installed out of my own control. But be sure to
275 change the names /in/ the files too, not just the names /of/ the files,
276 or systemd will be complaining about the stupid admin trying to give it
277 nonsensical unit files to run. =:^P
278
279 Also, one last caution. I chose to retype most of the above files
280 manually, getting back into what they did and how as I did so, instead of
281 copy/pasting them and then sitting there studying them to remember how
282 they worked. Not so boring that way, but there's possibly a few typos I
283 missed. They should be reasonably obvious and easy to fix, tho, if I did
284 miss some...
285
286 --
287 Duncan - List replies preferred. No HTML msgs.
288 "Every nonfree program has a lord, a master --
289 and if you use the program, he is your master." Richard Stallman

Replies

Subject Author
Re: [gentoo-amd64] Re: Systemd migration: opinion and questions Marc Joliet <marcec@×××.de>