diff --git a/Puppetfile b/Puppetfile index 65438bf7f..1346f40e3 100644 --- a/Puppetfile +++ b/Puppetfile @@ -19,7 +19,7 @@ mod 'cinder', :git => 'https://github.com/stackforge/puppet-cinder.git' mod 'common', - :commit => '2c0ed2844c606fd806bde0c02e47e79c88fab4a9', + :commit => '165e2adc3ab559597f461e6eae3eb004967070f9', :git => 'https://github.com/purpleidea/puppet-common.git' mod 'concat', diff --git a/common/examples/counter-example.pp b/common/examples/counter-example.pp new file mode 100644 index 000000000..dc47951c1 --- /dev/null +++ b/common/examples/counter-example.pp @@ -0,0 +1,10 @@ +# example use of silent counter + +include ::common::counter # that's it! + +# NOTE: we only see the notify message. no other exec/change is shown! +notify { 'counter': + message => "Value is: ${::common_counter_simple}", +} + +# vim: ts=8 diff --git a/common/lib/facter/counter.rb b/common/lib/facter/counter.rb new file mode 100644 index 000000000..819b5053b --- /dev/null +++ b/common/lib/facter/counter.rb @@ -0,0 +1,70 @@ +# Increment an ID so that it is unique to each puppet run. +# Copyright (C) 2012-2013+ James Shubin +# Written by James Shubin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +require 'facter' + +# find the module_vardir +dir = Facter.value('puppet_vardirtmp') # nil if missing +if dir.nil? # let puppet decide if present! + dir = Facter.value('puppet_vardir') + if dir.nil? + var = nil + else + var = dir.gsub(/\/$/, '')+'/'+'tmp/' # ensure trailing slash + end +else + var = dir.gsub(/\/$/, '')+'/' +end + +if var.nil? + # if we can't get a valid vardirtmp, then we can't continue + module_vardir = nil + counterdir = nil + counter_simple = nil +else + module_vardir = var+'common/' + counterdir = module_vardir+'counter/' + counter_simple = counterdir+'simple' +end + +# NOTE: module specific mkdirs, needed to ensure there is no blocking/deadlock! +if not(var.nil?) and not File.directory?(var) + Dir::mkdir(var) +end + +if not(module_vardir.nil?) and not File.directory?(module_vardir) + Dir::mkdir(module_vardir) +end + +if not(counterdir.nil?) and not File.directory?(counterdir) + Dir::mkdir(counterdir) +end + +value = 0 # default value to use if file doesn't exist +# create the fact if the counter file contains a valid int, or if it's empty: 0 +if not(counter_simple.nil?) and File.exist?(counter_simple) + # an empty file will output a value of 0 with this idiomatic line... + value = File.open(counter_simple, 'r').read.strip.to_i # read into int +end +Facter.add('common_counter_simple') do + #confine :operatingsystem => %w{CentOS, RedHat, Fedora} + setcode { + value + } +end + +# vim: ts=8 diff --git a/common/manifests/again/delta.pp b/common/manifests/again/delta.pp index 2c2c27ed9..c9f6905cb 100644 --- a/common/manifests/again/delta.pp +++ b/common/manifests/again/delta.pp @@ -36,6 +36,7 @@ default => '', } + # TODO: add --name '${name}' as a uid to prevent running of duplicates! $arglist = ["--delta ${valid_delta}", "${valid_start_timer_now}"] $args = join(delete($arglist, ''), ' ') diff --git a/common/manifests/counter.pp b/common/manifests/counter.pp new file mode 100644 index 000000000..644162c32 --- /dev/null +++ b/common/manifests/counter.pp @@ -0,0 +1,75 @@ +# Increment an ID so that it is unique to each puppet run. +# Copyright (C) 2012-2013+ James Shubin +# Written by James Shubin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +class common::counter { + + include common::vardir + + #$vardir = $::common::vardir::module_vardir # with trailing slash + $vardir = regsubst($::common::vardir::module_vardir, '\/$', '') + + # store 'counter' in a separate directory + file { "${vardir}/counter/": + ensure => directory, # make sure this is a directory + recurse => true, # don't recurse into directory + purge => true, # don't purge unmanaged files + force => true, # don't purge subdirs and links + require => File["${vardir}/"], + } + + file { "${vardir}/counter/increment.py": + # NOTE: this is actually templated, but no templating + # is actually being used. This gives us the option to + # pass in some variables if we decide we would like a + # way to get values in other than via command line... + # we could pass in some environ data or other data... + content => template('common/counter/increment.py.erb'), + owner => root, + group => root, + mode => 755, + ensure => present, + require => File["${vardir}/counter/"], + } + + # NOTE: this is a simple counter. it is 'simple' because it is probably + # possible to build more complex counters that can ensure that only one + # increment happens per puppet run if multiple puppets run in parallel! + # in other words: this simple counter doesn't do any file locking stuff + file { "${vardir}/counter/simple": + owner => root, + group => root, + mode => 644, + ensure => present, + require => File["${vardir}/counter/"], + } + + # this command silently increments the counter without displaying logs! + exec { 'counter': + # echo an error message and be false, if the incrementing fails + command => '/bin/echo "common::counter failed" && /bin/false', + # NOTE: this 'unless' is actually _NOT_ idempotent as is normal + # it should always return true, unless there's an error running + unless => "${vardir}/counter/increment.py '${vardir}/counter/simple'", + logoutput => on_failure, + require => [ + File["${vardir}/counter/increment.py"], + File["${vardir}/counter/simple"], + ], + } +} + +# vim: ts=8 diff --git a/common/manifests/frag/frag.pp b/common/manifests/frag/frag.pp index 3938006d9..4dd73449f 100644 --- a/common/manifests/frag/frag.pp +++ b/common/manifests/frag/frag.pp @@ -36,7 +36,7 @@ } # this is the parent (basename) dir of $name which is special if i frag - $frag_d = sprintf("%s/", regsubst($name, '((\/[\w.-]+)*)(\/)([\w.-]+)', '\1')) + $frag_d = sprintf("%s/", regsubst("${name}", '((\/[\w.-]+)*)(\/)([\w.-]+)', '\1')) # the file (used to set perms and as a placeholder so it's not deleted) file { "${name}": @@ -96,10 +96,10 @@ $source = '' # TODO: add more file object features if someone needs them or if bored ) { - # finds the file name in a complete path; eg: /tmp/dir/file => file - #$x = regsubst($name, '(\/[\w.]+)*(\/)([\w.]+)', '\3') + # finds the file basename in a complete path; eg: /tmp/dir/file => file + #$x = regsubst("${name}", '(\/[\w.]+)*(\/)([\w.]+)', '\3') # finds the basepath in a complete path; eg: /tmp/dir/file => /tmp/dir/ - $d = sprintf("%s/", regsubst($name, '((\/[\w.-]+)*)(\/)([\w.-]+)', '\1')) + $d = sprintf("%s/", regsubst("${name}", '((\/[\w.-]+)*)(\/)([\w.-]+)', '\1')) # the file fragment file { "${name}": diff --git a/common/manifests/init.pp b/common/manifests/init.pp index fa9bec3eb..5af8ac9de 100644 --- a/common/manifests/init.pp +++ b/common/manifests/init.pp @@ -19,5 +19,5 @@ class common { - } +# vim: ts=8 diff --git a/common/templates/again/again.py.erb b/common/templates/again/again.py.erb index 5eb1c3125..ef06b66c1 100755 --- a/common/templates/again/again.py.erb +++ b/common/templates/again/again.py.erb @@ -183,7 +183,7 @@ if fork == 0: # child os.execvpe(argv[0], argv, env) # this command does not return! else: # parent - print "pid: %d will try to puppet again..." % fork + print "pid: %d will try to run puppet again..." % fork sys.exit(0) # let puppet exit successfully! # vim: ts=8 diff --git a/common/templates/counter/increment.py.erb b/common/templates/counter/increment.py.erb new file mode 100755 index 000000000..e416ad1dd --- /dev/null +++ b/common/templates/counter/increment.py.erb @@ -0,0 +1,61 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" +Read in a single integer from a text file, increment it, and write it back. + +This script is usually only executed by a puppet exec type. +""" +# Increment an ID so that it is unique to each puppet run. +# Copyright (C) 2012-2013+ James Shubin +# Written by James Shubin +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import os +import sys +if len(sys.argv) != 2: sys.exit(1) + +# parse the commandline, and don't run the increment if --noop is used :) +pid = os.getpid() # my pid +ppid = os.getppid() # parent pid + +# parse parent cmdline +with open("/proc/%d/cmdline" % ppid, 'r') as f: + cmdline = f.read() +argv = cmdline.split("\0") # separated by nulls (the: ^@ character in vim) +if argv[-1] == '': argv.pop() # remove empty element at end of list if exists + +# TODO: does the noop detection work when we run as a service ? (probably not!) +if '--noop' in argv: + sys.exit(0) + +# now do the actual incremental work... +f = open(sys.argv[1], 'r') +a = [l.strip() for l in f.readlines() if l.strip() != ''] +f.close() +if len(a) == 0: + i = 0 +elif len(a) != 1: sys.exit(2) +else: + try: + i = int(a[0]) + except ValueError, e: + sys.exit(3) + +#print(i) +f = open(sys.argv[1], 'w') +f.write("%d\n" % (i+1)) +f.close() +sys.exit(0) +