diff --git a/site-modules/profile/functions/cron/validate_field.pp b/site-modules/profile/functions/cron/validate_field.pp index 015c6377..d0273fff 100644 --- a/site-modules/profile/functions/cron/validate_field.pp +++ b/site-modules/profile/functions/cron/validate_field.pp @@ -1,157 +1,173 @@ function profile::cron::validate_field( String $field, Variant[Integer, String, Array[Variant[Integer, String]]] $value, Optional[Array[String]] $valid_strings, Optional[Tuple[Integer, Integer]] $int_range, + Optional[String] $seed = undef, Boolean $arrays_valid = true, ) >> Tuple[Optional[String], Array[String]] { if $value =~ Array and !$arrays_valid { return [undef, ["Cannot nest Arrays in value for ${field}"]] } $_valid_strings = pick_default($valid_strings, []) + $_int_range = pick_default($int_range, [0, 0]) case $value { Array: { $ret = $value.map |$_value| { profile::cron::validate_field( $field, $_value, $valid_strings, $int_range, + $seed, false, ) } $_failed_values = $ret.filter |$_value| { $_value[0] == undef } if empty($_failed_values) { return [$ret.map |$_value| {$_value[0]}.join(','), []] } else { return [undef, $_failed_values.map |$_value| { $_value[1] }.flatten] } } *($_valid_strings + ['*']): { return [$value, []] } + 'fqdn_rand': { + [$_min, $_max] = $_int_range + return [$_min + fqdn_rand($_max - $_min + 1, "${seed}_${field}"), []] + } + /^\d+$/: { return profile::cron::validate_field( $field, Integer($value, 10), $valid_strings, $int_range, + $seed, $arrays_valid, ) } /[ ,]/: { return profile::cron::validate_field( $field, $value.split('[ ,]'), $valid_strings, $int_range, + $seed, $arrays_valid, ) } /^([0-9a-z]+)-([0-9a-z]+)$/: { $min_valid = profile::cron::validate_field( $field, $1, $valid_strings, $int_range, + $seed, false, ) $max_valid = profile::cron::validate_field( $field, $2, $valid_strings, $int_range, + $seed, false, ) $_errors = $min_valid[1] + $max_valid[1] if empty($_errors) { $_parsed_min = $min_valid[0] $_parsed_max = $max_valid[0] return ["${_parsed_min}-${_parsed_max}", []] } else { return [undef, $_errors] } } /^([0-9a-z]+)-([0-9a-z]+)\/(\d+)$/: { $min_valid = profile::cron::validate_field( $field, $1, $valid_strings, $int_range, + $seed, false, ) $max_valid = profile::cron::validate_field( $field, $2, $valid_strings, $int_range, + $seed, false, ) $interval_valid = profile::cron::validate_field( $field, Integer($3, 10), [], $int_range, + $seed, false, ) $_errors = $min_valid[1] + $max_valid[1] + $interval_valid[1] if empty($_errors) { $_parsed_min = $min_valid[0] $_parsed_max = $max_valid[0] $_parsed_interval = $interval_valid[0] return ["${_parsed_min}-${_parsed_max}/${_parsed_interval}", []] } else { return [undef, $_errors] } } /^\*\/(\d+)$/: { $interval_valid = profile::cron::validate_field( $field, Integer($1, 10), [], $int_range, + $seed, false, ) if empty($interval_valid[1]) { $_parsed_interval = $interval_valid[0] return ["*/${_parsed_interval}", []] } else { return $interval_valid } } String: { return [undef, ["Could not parse value ${value} for field ${field}"]] } Integer: { - [$_min, $_max] = pick_default($int_range, [0, 0]) + [$_min, $_max] = $_int_range if $_min <= $value and $value <= $_max { return [String($value), []] } else { return [undef, ["Value ${value} out of range ${_min}-${_max} for field ${field}"]] } } default: { return [undef, ["Unknown type ${value} for field ${field}"]] } } } diff --git a/site-modules/profile/manifests/cron/d.pp b/site-modules/profile/manifests/cron/d.pp index 03c1c0f1..5ba8d1d7 100644 --- a/site-modules/profile/manifests/cron/d.pp +++ b/site-modules/profile/manifests/cron/d.pp @@ -1,75 +1,76 @@ # Add a cron.d snippet to the /etc/puppet-cron.d directory define profile::cron::d( String $command, String $unique_tag = $title, String $target = 'default', Optional[Variant[Integer, String, Array[Variant[Integer, String]]]] $minute = undef, Optional[Variant[Integer, String, Array[Variant[Integer, String]]]] $hour = undef, Optional[Variant[Integer, String, Array[Variant[Integer, String]]]] $monthday = undef, Optional[Variant[Integer, String, Array[Variant[Integer, String]]]] $month = undef, Optional[Variant[Integer, String, Array[Variant[Integer, String]]]] $weekday = undef, Optional[Enum['@reboot', '@yearly', '@annually', '@monthly', '@weekly', '@daily', '@midnight', '@hourly']] $special = undef, String $user = 'root', Optional[String] $random_seed = undef, ) { include profile::cron $_params = { - 'minute' => $minute, - 'hour' => $hour, + 'minute' => $minute, + 'hour' => $hour, 'monthday' => $monthday, - 'month' => $month, - 'weekday' => $weekday, + 'month' => $month, + 'weekday' => $weekday, } $_int_limits = { 'minute' => [0, 59], 'hour' => [0, 23], 'monthday' => [1, 31], 'month' => [1, 12], 'weekday' => [0, 7], } $_str_values = { 'month' => ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'], 'weekday' => ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'], } if $special != undef { $_defined_params = $_params.filter |$field, $value| { $value == undef } unless empty($_defined_params) { $_defined_fields = keys($_defined_params).each |$field| {"'${field}'"}.join(', ') fail("profile::cron::d parameter 'special' is exclusive with ${_defined_fields}.") } } $_parsed_params = $_params.map |$field, $value| { [$field] + profile::cron::validate_field( $field, pick_default($value, '*'), $_str_values[$field], $_int_limits[$field], + $random_seed, ) } $_parse_errors = $_parsed_params.filter |$value| { $value[1] == undef }.map |$value| { $value[2] }.flatten unless empty($_parse_errors) { $_str_parse_errors = $_parse_errors.join(', ') fail("Parse errors in profile::cron::d: ${_str_parse_errors}") } $_params_hash = $_parsed_params.map |$value| { $value[0,2] }.hash if !defined(Profile::Cron::File[$target]) { profile::cron::file {$target:} } concat_fragment {"profile::cron::${unique_tag}": order => '10', content => template('profile/cron/snippet.erb'), tag => "profile::cron::${target}", target => "profile::cron::${target}", } }