diff --git a/files/concatfragments.sh b/files/concatfragments.sh index 12b815e..05b6527 100755 --- a/files/concatfragments.sh +++ b/files/concatfragments.sh @@ -1,134 +1,140 @@ #!/bin/sh # Script to concat files to a config file. # # Given a directory like this: # /path/to/conf.d # |-- fragments # | |-- 00_named.conf # | |-- 10_domain.net # | `-- zz_footer # # The script supports a test option that will build the concat file to a temp location and # use /usr/bin/cmp to verify if it should be run or not. This would result in the concat happening # twice on each run but gives you the option to have an unless option in your execs to inhibit rebuilds. # # Without the test option and the unless combo your services that depend on the final file would end up # restarting on each run, or in other manifest models some changes might get missed. # # OPTIONS: # -o The file to create from the sources # -d The directory where the fragments are kept # -t Test to find out if a build is needed, basically concats the files to a temp # location and compare with what's in the final location, return codes are designed # for use with unless on an exec resource # -w Add a shell style comment at the top of the created file to warn users that it # is generated by puppet # -f Enables the creation of empty output files when no fragments are found # -n Sort the output numerically rather than the default alpha sort # # the command: # # concatfragments.sh -o /path/to/conffile.cfg -d /path/to/conf.d # # creates /path/to/conf.d/fragments.concat and copies the resulting # file to /path/to/conffile.cfg. The files will be sorted alphabetically # pass the -n switch to sort numerically. # # The script does error checking on the various dirs and files to make # sure things don't fail. OUTFILE="" WORKDIR="" TEST="" FORCE="" WARN="" SORTARG="" +ENSURE_NEW_LINE="" PATH=/sbin:/usr/sbin:/bin:/usr/bin ## Well, if there's ever a bad way to do things, Nexenta has it. ## http://nexenta.org/projects/site/wiki/Personalities unset SUN_PERSONALITY while getopts "o:s:d:tnw:f" options; do case $options in o ) OUTFILE=$OPTARG;; d ) WORKDIR=$OPTARG;; n ) SORTARG="-n";; w ) WARNMSG="$OPTARG";; f ) FORCE="true";; t ) TEST="true";; + l ) ENSURE_NEW_LINE="true";; * ) echo "Specify output file with -o and fragments directory with -d" exit 1;; esac done # do we have -o? if [ x${OUTFILE} = "x" ]; then echo "Please specify an output file with -o" exit 1 fi # do we have -d? if [ x${WORKDIR} = "x" ]; then echo "Please fragments directory with -d" exit 1 fi # can we write to -o? if [ -f ${OUTFILE} ]; then if [ ! -w ${OUTFILE} ]; then echo "Cannot write to ${OUTFILE}" exit 1 fi else if [ ! -w `dirname ${OUTFILE}` ]; then echo "Cannot write to `dirname ${OUTFILE}` to create ${OUTFILE}" exit 1 fi fi # do we have a fragments subdir inside the work dir? if [ ! -d "${WORKDIR}/fragments" ] && [ ! -x "${WORKDIR}/fragments" ]; then echo "Cannot access the fragments directory" exit 1 fi # are there actually any fragments? if [ ! "$(ls -A ${WORKDIR}/fragments)" ]; then if [ x${FORCE} = "x" ]; then echo "The fragments directory is empty, cowardly refusing to make empty config files" exit 1 fi fi cd ${WORKDIR} if [ "x${WARNMSG}" = "x" ]; then : > "fragments.concat" else printf '%s\n' "$WARNMSG" > "fragments.concat" fi +if [ x${ENSURE_NEW_LINE} != x ]; then + find fragments/ -type f -follow -print0 | xargs -0 -I '{}' sh -c 'if [ -n "$(tail -c 1 < {} )" ]; then echo >> {} ; fi' +fi + # find all the files in the fragments directory, sort them numerically and concat to fragments.concat in the working dir IFS_BACKUP=$IFS IFS=' ' for fragfile in `find fragments/ -type f -follow | LANG=C sort ${SORTARG}` do cat $fragfile >> concat.fragment done IFS=$IFS_BACKUP if [ x${TEST} = "x" ]; then # This is a real run, copy the file to outfile cp fragments.concat ${OUTFILE} RETVAL=$? else # Just compare the result to outfile to help the exec decide cmp ${OUTFILE} fragments.concat RETVAL=$? fi exit $RETVAL diff --git a/manifests/init.pp b/manifests/init.pp index cba8223..2ecafcd 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,177 +1,190 @@ # == Define: concat # # Sets up so that you can use fragments to build a final config file, # # === Options: # # [*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. # [*mode*] # The mode of the final file # [*owner*] # Who will own the file # [*group*] # Who will own the 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 # [*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 # # === Actions: # * Creates fragment directories if it didn't exist already # * Executes the concatfragments.sh 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 # # === Aliases: # # * The exec can notified using Exec["concat_/path/to/file"] or # Exec["concat_/path/to/directory"] # * The final file can be referened as File["/path/to/file"] or # File["concat_/path/to/file"] # define concat( $path = $name, $owner = $::id, $group = $concat::setup::root_group, $mode = '0644', $warn = false, $force = false, $backup = 'puppet', $replace = true, $gnu = undef, - $order='alpha' + $order='alpha', + $ensure_new_line = false ) { include concat::setup $safe_name = regsubst($name, '/', '_', 'G') $concatdir = $concat::setup::concatdir $version = $concat::setup::majorversion $fragdir = "${concatdir}/${safe_name}" $concat_name = 'fragments.concat.out' $default_warn_message = '# This file is managed by Puppet. DO NOT EDIT.' case $warn { 'true', true, yes, on: { $warnmsg = $default_warn_message } 'false', false, no, off: { $warnmsg = '' } default: { $warnmsg = $warn } } $warnmsg_escaped = regsubst($warnmsg, "'", "'\\\\''", 'G') $warnflag = $warnmsg_escaped ? { '' => '', default => "-w '${warnmsg_escaped}'" } case $force { 'true', true, yes, on: { $forceflag = '-f' } 'false', false, no, off: { $forceflag = '' } default: { fail("Improper 'force' value given to concat: ${force}") } } case $order { numeric: { $orderflag = '-n' } alpha: { $orderflag = '' } default: { fail("Improper 'order' value given to concat: ${order}") } } + case $ensure_new_line { + 'true', true, yes, on: { + $newlineflag = '-l' + } + 'false', false, no, off: { + $newlineflag = '' + } + default: { + fail("Improper 'ensure_new_line' value given to concat: ${ensure_new_line}") + } + } + File { owner => $::id, group => $group, mode => $mode, backup => $backup, replace => $replace } file { $fragdir: ensure => directory, } $source_real = $version ? { 24 => 'puppet:///concat/null', default => undef, } file { "${fragdir}/fragments": ensure => directory, force => true, ignore => ['.svn', '.git', '.gitignore'], notify => Exec["concat_${name}"], purge => true, recurse => true, source => $source_real, } file { "${fragdir}/fragments.concat": ensure => present, } file { "${fragdir}/${concat_name}": ensure => present, } file { $name: ensure => present, path => $path, alias => "concat_${name}", group => $group, mode => $mode, owner => $owner, source => "${fragdir}/${concat_name}", } exec { "concat_${name}": alias => "concat_${fragdir}", - command => "${concat::setup::concatdir}/bin/concatfragments.sh -o ${fragdir}/${concat_name} -d ${fragdir} ${warnflag} ${forceflag} ${orderflag}", + command => "${concat::setup::concatdir}/bin/concatfragments.sh -o ${fragdir}/${concat_name} -d ${fragdir} ${warnflag} ${forceflag} ${orderflag} ${newlineflag}", notify => File[$name], require => [ File[$fragdir], File["${fragdir}/fragments"], File["${fragdir}/fragments.concat"], ], subscribe => File[$fragdir], - unless => "${concat::setup::concatdir}/bin/concatfragments.sh -o ${fragdir}/${concat_name} -d ${fragdir} -t ${warnflag} ${forceflag} ${orderflag}", + unless => "${concat::setup::concatdir}/bin/concatfragments.sh -o ${fragdir}/${concat_name} -d ${fragdir} -t ${warnflag} ${forceflag} ${orderflag} ${newlineflag}", } if $::id == 'root' { Exec["concat_${name}"] { user => root, group => $group, } } } # vim:sw=2:ts=2:expandtab:textwidth=79