diff --git a/probes/DeterministicDelay b/probes/DeterministicDelay new file mode 100755 index 0000000..cca9fd3 --- /dev/null +++ b/probes/DeterministicDelay @@ -0,0 +1,79 @@ +#! /usr/bin/env python3 + +import argparse +import hashlib +import subprocess +import time + +parser = argparse.ArgumentParser( + prog='DeterministicDelay', + description=('Delays running a command by a consistent amount of time. ' + 'This may be useful in spreading the load out from frequently running cronjobs. ' + 'When frequency is specified, delays longer than the frequency will exit without executing, ' + 'and the next execution will have a possibility. ' + 'i.e. -d 7d -f 1d means the script is run once per day, but the only 1/7 executions will really run.'), + epilog=None) + +parser.add_argument('-d', required=False, dest='delay', + help=('The maximum amount of time to delay. 60 seconds is the default, ' + 'suffix with s (the default), m, h, or d for seconds, minutes, hours, or days.')) +parser.add_argument('-f', required=False, dest='frequency', + help=('Frequency of submission. ' + 'Suffix with s (the default), m, h, or d for seconds, minutes, hours, or days.')) +parser.add_argument('commands', nargs='+', help="The commands to run") +args = parser.parse_args() + +command_hash = hashlib.sha256(bytes(str(args.commands), 'utf-8')) +checksum = int(command_hash.hexdigest(), 16) + +frequency = None +if args.frequency: + if args.frequency[-1] in ['s', 'm', 'h', 'd']: + frequency_value, frequency_unit = args.frequency[:-1], args.frequency[-1] + if frequency_unit == 'm': + frequency = int(frequency_value) * 60 + elif frequency_unit == 'h': + frequency = int(frequency_value) * 60 * 60 + elif frequency_unit == 'd': + frequency = int(frequency_value) * 24 * 60 * 60 + else: + frequency = int(frequency_value) + else: + frequency = int(args.frequency) + +if not args.delay: + max_delay = 60 +else: + if args.delay[-1] in ['s', 'm', 'h', 'd']: + delay_value, delay_unit = args.delay[:-1], args.delay[-1] + if delay_unit == 'm': + max_delay = int(delay_value) * 60 + elif delay_unit == 'h': + max_delay = int(delay_value) * 60 * 60 + elif delay_unit == 'd': + max_delay = int(delay_value) * 24 * 60 * 60 + else: + max_delay = int(delay_value) + else: + max_delay = int(args.delay) + +delay = checksum % max_delay + +if frequency and delay: + epoch = time.time() + if epoch % delay > frequency: + print(f'Exiting. time: {epoch % max_delay} max: {max_delay} f: {frequency}') + exit() + else: + print(f'Running. time: {epoch % max_delay} max: {max_delay} f: {frequency}') + delay = checksum % frequency + +print(f"Sleeping {delay}s") +time.sleep(delay) + +executed = subprocess.run(args.commands, capture_output=True) + +print("STDOUT") +print(executed.stdout) +print("STDERR") +print(executed.stderr) diff --git a/probes/Dockerfile b/probes/Dockerfile index 8290b13..731b9ee 100644 --- a/probes/Dockerfile +++ b/probes/Dockerfile @@ -15,6 +15,7 @@ ADD oic.rpm /tmp RUN dnf install -y epel-release.noarch && \ dnf upgrade -y && \ dnf install -y \ + cronie-noanacron \ git \ gcc \ libnsl \ @@ -49,5 +50,6 @@ RUN git clone https://github.com/rucio/probes.git ADD rucio.config.default.cfg /tmp/ ADD run-probes.sh / +ADD DeterministicDelay / ENTRYPOINT ["/run-probes.sh"] diff --git a/probes/run-probes.sh b/probes/run-probes.sh index b074079..59dbbac 100755 --- a/probes/run-probes.sh +++ b/probes/run-probes.sh @@ -18,14 +18,20 @@ if [ ! -z "$RUCIO_PRINT_CFG" ]; then echo "" fi -cp /etc/jobber-config/dot-jobber.yaml /root/.jobber +if [ ! -z "$RUCIO_USING_CRON" ]; then + echo "Setting up and starting cron" + cp /etc/cron.rucio/probes-crontab /etc/cron.d/ + crond -n -s +else + cp /etc/jobber-config/dot-jobber.yaml /root/.jobber -echo "Starting Jobber" -/usr/local/libexec/jobbermaster & + echo "Not using cron. Starting Jobber" + /usr/local/libexec/jobbermaster & -sleep 5 + sleep 5 -echo -echo "============= Jobber log file =============" + echo + echo "============= Jobber log file =============" -tail -f /var/log/jobber-runs + tail -f /var/log/jobber-runs +fi