-# == Define: concat
+# @summary
+# Manages a file, compiled from one or more text fragments.
#
-# Sets up so that you can use fragments to build a final config file,
+# @example
+# concat { '/tmp/concat':
+# ensure => present,
+# owner => 'root',
+# group => 'root',
+# mode => '0644',
+# }
#
-# === Options:
+# @param backup
+# Specifies whether (and how) to back up the destination file before overwriting it. Your value gets passed on to Puppet's native file
+# resource for execution. Valid options: true, false, or a string representing either a target filebucket or a filename extension
+# beginning with ".".
#
-# [*ensure*]
-# Present/Absent
-# [*path*]
-# The path to the final file. Use this in case you want to differentiate
-# between the name of a resource and the file path. Note: Use the name you
-# provided in the target of your fragments.
-# [*owner*]
-# Who will own the file
-# [*group*]
-# Who will own the file
-# [*mode*]
-# The mode of the final file
-# [*force*]
-# Enables creating empty files if no fragments are present
-# [*warn*]
-# Adds a normal shell style comment top of the file indicating that it is
-# built by puppet
-# [*force*]
-# [*backup*]
-# Controls the filebucketing behavior of the final file and see File type
-# reference for its use. Defaults to 'puppet'
-# [*replace*]
-# Whether to replace a file that already exists on the local system
-# [*order*]
-# [*ensure_newline*]
-# [*gnu*]
-# Deprecated
+# @param ensure
+# Specifies whether the destination file should exist. Setting to 'absent' tells Puppet to delete the destination file if it exists, and
+# negates the effect of any other parameters.
#
-# === Actions:
-# * Creates fragment directories if it didn't exist already
-# * Executes the concatfragments.rb script to build the final file, this
-# script will create directory/fragments.concat. Execution happens only
-# when:
-# * The directory changes
-# * fragments.concat != final destination, this means rebuilds will happen
-# whenever someone changes or deletes the final file. Checking is done
-# using /usr/bin/cmp.
-# * The Exec gets notified by something else - like the concat::fragment
-# define
-# * Copies the file over to the final destination using a file resource
+# @param ensure_newline
+# Specifies whether to add a line break at the end of each fragment that doesn't already end in one.
#
-# === Aliases:
+# @param format
+# Specify what data type to merge the fragments as. Valid options: 'plain', 'yaml', 'json', 'json-array', 'json-pretty',
+# 'json-array-pretty'.
#
-# * The exec can notified using Exec["concat_/path/to/file"] or
-# Exec["concat_/path/to/directory"]
-# * The final file can be referenced as File["/path/to/file"] or
-# File["concat_/path/to/file"]
+# @param force
+# Specifies whether to merge data structures, keeping the values with higher order. Used when format is specified as a value other than
+# 'plain'.
+#
+# @param group
+# Specifies a permissions group for the destination file. Valid options: a string containing a group name or integer containing a gid.
+#
+# @param mode
+# Specifies the permissions mode of the destination file. Valid options: a string containing a permission mode value in octal notation.
+#
+# @param order
+# Specifies a method for sorting your fragments by name within the destination file. You can override this setting for individual
+# fragments by adjusting the order parameter in their concat::fragment declarations.
+#
+# @param owner
+# Specifies the owner of the destination file. Valid options: a string containing a username or integer containing a uid.
+#
+# @param path
+# Specifies a destination file for the combined fragments.
+#
+# @param replace
+# Specifies whether to overwrite the destination file if it already exists.
+#
+# @param selinux_ignore_defaults
+# See the file type's selinux_ignore_defaults documentention:
+# https://docs.puppetlabs.com/references/latest/type.html#file-attribute-selinux_ignore_defaults
+#
+# @param selrange
+# See the file type's selrange documentention: https://docs.puppetlabs.com/references/latest/type.html#file-attribute-selrange
+#
+# @param selrole
+# See the file type's selrole documentention: https://docs.puppetlabs.com/references/latest/type.html#file-attribute-selrole
+#
+# @param seltype
+# See the file type's seltype documentention: https://docs.puppetlabs.com/references/latest/type.html#file-attribute-seltype
+#
+# @param seluser
+# See the file type's seluser documentention: https://docs.puppetlabs.com/references/latest/type.html#file-attribute-seluser
+#
+# @param show_diff
+# Specifies whether to set the show_diff parameter for the file resource. Useful for hiding secrets stored in hiera from insecure
+# reporting methods.
+#
+# @param validate_cmd
+# Specifies a validation command to apply to the destination file.
+#
+# @param warn
+# Specifies whether to add a header message at the top of the destination file. Valid options: the booleans true and false, or a string
+# to serve as the header.
+# If you set 'warn' to true, concat adds the following line with an order of 0:
+# `# This file is managed by Puppet. DO NOT EDIT.`
+# Before 2.0.0, this parameter would add a newline at the end of the warn message. To improve flexibilty, this was removed. Please add
+# it explicitly if you need it.
#
define concat(
- $ensure = 'present',
- $path = $name,
- $owner = undef,
- $group = undef,
- $mode = '0644',
- $warn = false,
- $force = false,
- $backup = 'puppet',
- $replace = true,
- $order = 'alpha',
- $ensure_newline = false,
- $validate_cmd = undef,
- $gnu = undef
+ Enum['present', 'absent'] $ensure = 'present',
+ Stdlib::Absolutepath $path = $name,
+ Optional[Variant[String, Integer]] $owner = undef,
+ Optional[Variant[String, Integer]] $group = undef,
+ String $mode = '0644',
+ Variant[Boolean, String] $warn = false,
+ Boolean $show_diff = true,
+ Variant[Boolean, String] $backup = 'puppet',
+ Boolean $replace = true,
+ Enum['alpha','numeric'] $order = 'alpha',
+ Boolean $ensure_newline = false,
+ Optional[String] $validate_cmd = undef,
+ Optional[Boolean] $selinux_ignore_defaults = undef,
+ Optional[String] $selrange = undef,
+ Optional[String] $selrole = undef,
+ Optional[String] $seltype = undef,
+ Optional[String] $seluser = undef,
+ Optional[String] $format = 'plain',
+ Optional[Boolean] $force = false,
) {
- validate_re($ensure, '^present$|^absent$')
- validate_absolute_path($path)
- validate_string($owner)
- validate_string($group)
- validate_string($mode)
- if ! (is_string($warn) or $warn == true or $warn == false) {
- fail('$warn is not a string or boolean')
- }
- validate_bool($force)
- if ! concat_is_bool($backup) and ! is_string($backup) {
- fail('$backup must be string or bool!')
- }
- validate_bool($replace)
- validate_re($order, '^alpha$|^numeric$')
- validate_bool($ensure_newline)
- if $validate_cmd and ! is_string($validate_cmd) {
- fail('$validate_cmd must be a string')
- }
- if $gnu {
- warning('The $gnu parameter to concat is deprecated and has no effect')
- }
-
- include concat::setup
- $safe_name = regsubst($name, '[/:]', '_', 'G')
- $concatdir = $concat::setup::concatdir
- $fragdir = "${concatdir}/${safe_name}"
- $concat_name = 'fragments.concat.out'
- $script_command = $concat::setup::script_command
- $default_warn_message = '# This file is managed by Puppet. DO NOT EDIT.'
- $bool_warn_message = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release'
+ $safe_name = regsubst($name, '[\\\\/:~\n\s\+\*\(\)@]', '_', 'G')
+ $default_warn_message = "# This file is managed by Puppet. DO NOT EDIT.\n"
case $warn {
true: {
$warn_message = $default_warn_message
- }
- 'true', 'yes', 'on': {
- warning($bool_warn_message)
- $warn_message = $default_warn_message
+ $_append_header = true
}
false: {
$warn_message = ''
- }
- 'false', 'no', 'off': {
- warning($bool_warn_message)
- $warn_message = ''
+ $_append_header = false
}
default: {
$warn_message = $warn
+ $_append_header = true
}
}
- $warnmsg_escaped = regsubst($warn_message, '\'', '\'\\\'\'', 'G')
- $warnflag = $warnmsg_escaped ? {
- '' => '',
- default => "-w '${warnmsg_escaped}'"
- }
-
- $forceflag = $force ? {
- true => '-f',
- false => '',
- }
-
- $orderflag = $order ? {
- 'numeric' => '-n',
- 'alpha' => '',
- }
-
- $newlineflag = $ensure_newline ? {
- true => '-l',
- false => '',
- }
-
- File {
- backup => $backup,
- }
-
- # reset poisoned Exec defaults
- Exec {
- user => undef,
- group => undef,
- }
-
if $ensure == 'present' {
- file { $fragdir:
- ensure => directory,
- mode => '0750',
- }
-
- file { "${fragdir}/fragments":
- ensure => directory,
- mode => '0750',
- force => true,
- ignore => ['.svn', '.git', '.gitignore'],
- notify => Exec["concat_${name}"],
- purge => true,
- recurse => true,
- }
-
- file { "${fragdir}/fragments.concat":
- ensure => present,
- mode => '0640',
- }
-
- file { "${fragdir}/${concat_name}":
- ensure => present,
- mode => '0640',
- }
-
- file { $name:
- ensure => present,
- owner => $owner,
- group => $group,
- mode => $mode,
- replace => $replace,
- path => $path,
- alias => "concat_${name}",
- source => "${fragdir}/${concat_name}",
- backup => $backup,
- }
-
- # Only newer versions of puppet 3.x support the validate_cmd parameter
- if $validate_cmd {
- File[$name] {
- validate_cmd => $validate_cmd,
+ concat_file { $name:
+ tag => $safe_name,
+ path => $path,
+ owner => $owner,
+ group => $group,
+ mode => $mode,
+ selinux_ignore_defaults => $selinux_ignore_defaults,
+ selrange => $selrange,
+ selrole => $selrole,
+ seltype => $seltype,
+ seluser => $seluser,
+ replace => $replace,
+ backup => $backup,
+ show_diff => $show_diff,
+ order => $order,
+ ensure_newline => $ensure_newline,
+ validate_cmd => $validate_cmd,
+ format => $format,
+ force => $force,
+ }
+
+ if $_append_header {
+ concat_fragment { "${name}_header":
+ target => $name,
+ tag => $safe_name,
+ content => $warn_message,
+ order => '0',
}
}
-
- # remove extra whitespace from string interpolation to make testing easier
- $command = strip(regsubst("${script_command} -o \"${fragdir}/${concat_name}\" -d \"${fragdir}\" ${warnflag} ${forceflag} ${orderflag} ${newlineflag}", '\s+', ' ', 'G'))
-
- # make sure ruby is in the path for PE
- if defined('$is_pe') and $::is_pe {
- if $::kernel == 'windows' {
- $command_path = "${::env_windows_installdir}/bin:${::path}"
- } else {
- $command_path = "/opt/puppet/bin:${::path}"
- }
- } else {
- $command_path = $::path
- }
-
- # if puppet is running as root, this exec should also run as root to allow
- # the concatfragments.rb script to potentially be installed in path that
- # may not be accessible by a target non-root owner.
- exec { "concat_${name}":
- alias => "concat_${fragdir}",
- command => $command,
- notify => File[$name],
- subscribe => File[$fragdir],
- unless => "${command} -t",
- path => $command_path,
- require => [
- File[$fragdir],
- File["${fragdir}/fragments"],
- File["${fragdir}/fragments.concat"],
- ],
- }
} else {
- file { [
- $fragdir,
- "${fragdir}/fragments",
- "${fragdir}/fragments.concat",
- "${fragdir}/${concat_name}"
- ]:
- ensure => absent,
- force => true,
- }
-
- file { $path:
- ensure => absent,
+ concat_file { $name:
+ ensure => $ensure,
+ tag => $safe_name,
+ path => $path,
backup => $backup,
}
-
- $absent_exec_command = $::kernel ? {
- 'windows' => 'cmd.exe /c exit 0',
- default => 'true',
- }
-
- $absent_exec_path = $::kernel ? {
- 'windows' => $::path,
- default => '/bin:/usr/bin',
- }
-
- # Need to have an unless here for idempotency.
- exec { "concat_${name}":
- alias => "concat_${fragdir}",
- command => $absent_exec_command,
- unless => $absent_exec_command,
- path => $absent_exec_path,
- }
}
}
-
-# vim:sw=2:ts=2:expandtab:textwidth=79