Search code examples
chef-infrasystemd

Working around chef's systemd_unit resource


The chef systemd resource allows you to specify the service file via a content attribute (which takes a string or a hash). Both of these feel like an offensively bad idea; their example is:

systemd_unit 'sysstat-collect.timer' do
  content <<-EOU.gsub(/^\s+/, '')
  [Unit]
  Description=Run system activity accounting tool every 10 minutes

  [Timer]
  OnCalendar=*:00/10

  [Install]
  WantedBy=sysstat.service
  EOU

  action [:create, :enable]
end

This feel so very wrong... mixing my chef recipe with what should just be a config file (or templated file). I've tried various permuations of trying to write the file to my target (using cookbook_file) and then reading that back in to pass to content, but that also feels unsatisfying and so far hasn't worked.

Edit to ask a hopefully better question:

Is there some mechanism to use the chef systemd resource such that I'm not embedded configuration files as strings in the recipe file itself?


Solution

  • I thought much the same when I first started using systemd_unit, but now I look at it differently. I don't keep JSON, YAML, or TOML config files as templates, because they can be generated from attribute hashes. That ensures that they're syntactically correct and it's more flexible to change an attribute than a cookbook file. Units are INI-format files, so I treat them the same way.

    Sometimes, though, you just need to read a text file and pass it to a resource. I'm sure that this method can be improved, but it does the job.

    unit_temp_path = "#{Chef::Config[:file_cache_path]}/foo.service"
    
    cookbook_file unit_temp_path do
      action :create
    end
    
    systemd_unit 'foo.service' do
      # delay reading until convergence phase
      content lazy { ::File.read(unit_temp_path) }
      action :create
    end