From 817694b1fbf3fa5b2a547977a7e7cc884637cc19 Mon Sep 17 00:00:00 2001 From: Steve Traylen Date: Thu, 26 Sep 2019 17:28:25 +0200 Subject: [PATCH] New systemd::timer define type The defined type allows easy creation of the timer and service unit at the same time. Examples of usage ```puppet systemd::timer{'runoften.timer': timer_source => "puppet:///modules/${module_name}/runoften.timer", service_source => "puppet:///modules/${module_name}/runoften.service", } ``` or a trivial daily run as: ```puppet systemd::timer{'daily.timer': timer_content => "[Timer]\nOnCalendar=daily\nRandomizedDelaySec=1d\n", service_content => "[Service]\nType=oneshot\nExecStart=/usr/bin/touch /tmp/file", } ``` If neither `service_content` or `service_source` are specified then no service unit will be created. The service unit name can also be specified. ```puppet systemd::timer{'daily.timer': timer_content => "[Timer]\nOnCalendar=daily\nRandomizedDelaySec=1d\nUnit=touch-me-today.service", service_unit => 'touch-me-today.service', service_content => "[Service]\nType=oneshot\nExecStart=/usr/bin/touch /tmp/file", } ``` Fixes: 118 --- README.md | 76 ++++++++++++++++++++++++++ manifests/timer.pp | 106 +++++++++++++++++++++++++++++++++++++ spec/defines/timer_spec.rb | 85 +++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+) create mode 100644 manifests/timer.pp create mode 100644 spec/defines/timer_spec.rb diff --git a/README.md b/README.md index 65f2d9f2..c18ca256 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,82 @@ file { '/etc/tmpfiles.d/foo.conf': ~> Class['systemd::tmpfiles'] ``` +### timer units +Create a systemd timer unit and a systemd service unit to execute from +that timer + +The following will create a timer unit and a service unit file. +The execution of `systemctl daemon-reload` will occur. +When `active` and `enable` are set to `true` the puppet service `runoften.timer` will be +declared, started and enabled. + +```puppet +systemd::timer{'runoften.timer': + timer_source => "puppet:///modules/${module_name}/runoften.timer", + service_source => "puppet:///modules/${module_name}/runoften.service", + active => true, + enable => true, +} +``` + +A trivial daily run. +In this case enable and active are both unset and so the service `daily.timer` +is not declared by the `systemd::timer` type. + +```puppet +$_timer = @(EOT) +[Timer] +OnCalendar=daily +RandomizedDelaySec=1d +EOT + +$_service = @(EOT) +[Service] +Type=oneshot +ExecStart=/usr/bin/touch /tmp/file +EOT + +systemd::timer{'daily.timer': + timer_content => $_timer, + service_content => $_service, +} + +service{'daily.timer': + ensure => running, + subscribe => Systemd::Timer['daily.timer'], +} + +``` + +If neither `service_content` or `service_source` are specified then no +service unit will be created. + +The service unit name can also be specified. + +```puppet +$_timer = @(EOT) +[Timer] +OnCalendar=daily +RandomizedDelaySec=1d +Unit=touch-me-today.service +EOT + +$_service = @(EOT) +[Service] +Type=oneshot +ExecStart=/usr/bin/touch /tmp/file +EOT + + +systemd::timer{'daily.timer': + timer_content => $_timer, + service_unit => 'touch-me-today.service', + service_content => $_service, + active => true, + enable => true, +} +``` + ### service limits Manage soft and hard limits on various resources for executed processes. diff --git a/manifests/timer.pp b/manifests/timer.pp new file mode 100644 index 00000000..9a76937c --- /dev/null +++ b/manifests/timer.pp @@ -0,0 +1,106 @@ +# @summary Create a timer and optionally a service unit to execute with the timer unit +# +# @api public +# +# @see https://www.freedesktop.org/software/systemd/man/systemd.timer.html systemd.timer(5) +# +# @param name [Pattern['^.+\.timer$]] +# The target of the timer unit to create +# +# @param path +# The main systemd configuration path +# +# @param timer_content +# The full content of the timer unit file +# +# * Mutually exclusive with ``$timer_source`` +# +# @param timer_source +# The ``File`` resource compatible ``source`` +# +# * Mutually exclusive with ``$timer_content`` +# +# @param service_content +# The full content of the service unit file +# +# * Mutually exclusive with ``$service_source`` +# +# @param service_source +# The ``File`` resource compatible ``source`` +# +# * Mutually exclusive with ``$service_content`` +# +# @param owner +# The owner to set on the dropin file +# +# @param group +# The group to set on the dropin file +# +# @param mode +# The mode to set on the dropin file +# +# @param show_diff +# Whether to show the diff when updating dropin file +# +# @param service_unit +# If set then the service_unit will have this name. +# If not set the service unit has the same name +# as the timer unit with s/.timer/.service/ +# +# @param active +# If set to true or false the timer service will be maintained. +# If true the timer service will be running and enabled, if false it will +# explictly stopped and disabled. +# +# @param enable +# If set, will manage the state of the unit. +# +define systemd::timer ( + Enum['present', 'absent', 'file'] $ensure = 'present', + Stdlib::Absolutepath $path = '/etc/systemd/system', + Optional[String[1]] $timer_content = undef, + Optional[String[1]] $timer_source = undef, + Optional[String[1]] $service_content = undef, + Optional[String[1]] $service_source = undef, + String[1] $owner = 'root', + String[1] $group = 'root', + Stdlib::Filemode $mode = '0444', + Optional[Systemd::Unit] $service_unit = undef, + Boolean $show_diff = true, + Optional[Variant[Boolean, Enum['mask']]] $enable = undef, + Optional[Boolean] $active = undef, +) { + assert_type(Pattern['^.+\.timer$'],$name) + + if $service_unit { + $_service_unit = $service_unit + } else { + $_service_unit = "${basename($name,'.timer')}.service" + } + + if $service_content or $service_source { + systemd::unit_file{$_service_unit: + ensure => $ensure, + content => $service_content, + source => $service_source, + path => $path, + owner => $owner, + group => $group, + mode => $mode, + show_diff => $show_diff, + } + } + + systemd::unit_file{$name: + ensure => $ensure, + content => $timer_content, + source => $timer_source, + path => $path, + owner => $owner, + group => $group, + mode => $mode, + show_diff => $show_diff, + enable => $enable, + active => $active, + } +} diff --git a/spec/defines/timer_spec.rb b/spec/defines/timer_spec.rb new file mode 100644 index 00000000..55c0a2eb --- /dev/null +++ b/spec/defines/timer_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe 'systemd::timer' do + context 'supported operating systems' do + on_supported_os.each do |os, facts| + context "on #{os}" do + let(:facts) { facts } + + let(:title) { 'foobar.timer' } + + context('with timer_content and service_content') do + let(:params) do + { + timer_content: "[Timer]\nOnCalendar=weekly", + service_content: "[Service]\nExecStart=/bin/touch /tmp/foobar", + } + end + + it { is_expected.to compile.with_all_deps } + + it { + is_expected.to contain_systemd__unit_file('foobar.timer').with( + content: "[Timer]\nOnCalendar=weekly", + ) + } + + it { + is_expected.to contain_systemd__unit_file('foobar.service').with( + content: "[Service]\nExecStart=/bin/touch /tmp/foobar", + ) + } + end + + context('with timer_source and service_source') do + let(:params) do + { + timer_source: 'puppet:///timer', + service_source: 'puppet:///source', + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_systemd__unit_file('foobar.timer').with_source('puppet:///timer') } + it { is_expected.to contain_systemd__unit_file('foobar.service').with_source('puppet:///source') } + end + + context('with timer_source only set') do + let(:params) do + { + timer_source: 'puppet:///timer', + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_systemd__unit_file('foobar.timer').with_source('puppet:///timer') } + it { is_expected.not_to contain_systemd__unit_file('foobar.service') } + end + + context 'with service_unit specified' do + let(:params) do + { + timer_content: "[Timer]\nOnCalendar=weekly", + service_content: "[Service]\nExecStart=/bin/touch /tmp/foobar", + service_unit: 'gamma.service', + } + end + + it { is_expected.to contain_systemd__unit_file('foobar.timer').with_content("[Timer]\nOnCalendar=weekly") } + + it { is_expected.to contain_systemd__unit_file('gamma.service').with_content("[Service]\nExecStart=/bin/touch /tmp/foobar") } + end + + context 'with a bad timer name' do + let(:title) { 'foobar' } + + it { + expect { + is_expected.to compile.with_all_deps + }.to raise_error(%r{expects a match for}) + } + end + end + end + end +end