How to update grub with puppet?

For the quoting part, you could use augeasproviders's shellvar provider and force the quoting style:

shellvar { 'GRUB_CMDLINE_LINUX':
  ensure   => present,
  target   => '/etc/default/grub',
  value    => 'cgroup_enable=memory',
  quoted   => 'double',
}

This will use Augeas internaly (as a Ruby library) on the agent, only in a smarter way.

As for appending to existing values, there's two options:

  • Get the current value using a fact (use for example augeasfacter to retrieve it), analyze it in your manifest and append to it using the shellvar type;
  • Improve the shellvar provider so that it appends to the value instead of replacing it.

First option

The fact

The following file can be distributed in your module in ${modulepath}/${modulename}/lib/facter/grub_cmdline_linux.rb and deployed using pluginsync.

require 'augeas'
Facter.add(:grub_cmdline_linux) do
  setcode do
    Augeas.open(nil, '/', Augeas::NO_MODL_AUTOLOAD) do |aug|
      aug.transform(
        :lens => 'Shellvars.lns',
        :name => 'Grub',
        :incl => '/etc/default/grub',
        :excl => []
      )
      aug.load!
      aug.get('/files/etc/default/grub/GRUB_CMDLINE_LINUX').gsub(/['"]/, '')
    end
  end
end

This will return the current value of the fact as a string, and remove the quotes around the value. It requires the Augeas Ruby library on the agent, which I suppose you have if you use the augeas type already.

Puppet code

The next step is to make use of this value to check if your target value is included. You can split the string and use the stlib module functions for this:

$value = 'cgroup_enable=memory'

# Split string into an array
$grub_cmdline_linux_array = split($::grub_cmdline_linux, ' ')

# Check if $value is already there to determine new target value
$target = member($grub_cmdline_linux_array, $value) ? {
  true  => $grub_cmdline_linux_array,
  false => flatten([$grub_cmdline_linux_array, $value]),
}

# Enforce new target value
# Use the array and force the 'string' array type
shellvar { 'GRUB_CMDLINE_LINUX':
  ensure     => present,
  target     => '/etc/default/grub',
  value      => $target,
  array_type => string,
}

Run it

Notice: /Stage[main]//Shellvar[GRUB_CMDLINE_LINUX]/value: value changed ['quiet splash usbcore.old_scheme_first=1'] to 'quiet splash usbcore.old_scheme_first=1 cgroup_enable=memory'

Check idempotence:

Notice: Finished catalog run in 0.17 seconds

Second option

If you'd like to have a go at the second option, the best way would probably be to send a (nice) PR to augeasproviders's shellvar type adding an array_append parameter (or a better name):

shellvar { 'GRUB_CMDLINE_LINUX':
  ensure       => present,
  target       => '/etc/default/grub',
  value        => 'cgroup_enable=memory',
  array_append => true,
  array_type   => 'double',
}

This parameter would treat the value as an array, and append to the existing values if the value is not found already. This would require Ruby coding, but would be reusable in lots of other cases ;-)

Hint: this should happen here.


(for ubuntu users only)

As altering /etc/default/grub is not so nice ..

Just deploy /etc/default/grub.d/memory.cfg

GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX cgroup_enable=memory"

Then update-grub

(see the /etc/default/grub.d/*.cfg feature )