semaphoreui / semaphore

Modern UI and powerful API for Ansible, Terraform, OpenTofu, PowerShell and other DevOps tools.
https://semaphoreui.com
MIT License
10.58k stars 1.07k forks source link

Problem: Uncommon CRON format not working as expected #2241

Open Ken5998 opened 3 months ago

Ken5998 commented 3 months ago

Issue

We are using the latest version of semaphore: v2.10.22

We would like to execute some templates the last Wednesdey of the month, every month. On crontab.guru the CRON expression seems ok, but on semaphore it can't interpret it correctly (seems like it ignore the day of the week)

Today is friday 26 and the scheduler show that the template would be executed tomorrow instead of the next wednesdey.

15 9 25-31 3 or 15 9 25-31 WED

image image

Impact

Service (scheduled tasks, alerts), Ansible (task execution)

Installation method

Docker

Database

MySQL

Browser

Chrome, Microsoft Edge

Semaphore Version

v2.10.22-e44910d-1721658561

Ansible Version

No response

Logs & errors

No response

Manual installation - system information

No response

Configuration

No response

Additional information

No response

bmcatherasoo commented 2 months ago

I have the same issue in this version. @fiftin , could you please adjust the feature so it allows scheduling tasks in formats other than specific dates? For example, scheduling tasks for every third Monday of the month or using an uncommon CRON format.

Ken5998 commented 2 months ago

Currently we have a workaround to do so until this issue will be fixed. Instead of using the Schedule section in Semaphore, I have moved out the CRON logic.

I have created an Integration with an Alias that calls the interested task template and then externally (from the semaphore server or another server) with a curl command I call this alias with the CRON logic I need, it seems tricky but it's really easy.

On the server I use the ncal package to obtain the correct information about the last wednesday of the current month, then on crontab I define the execution every wednesday but only once per month will be executed.

crontab

0 3 * * 3 /usr/local/bin/unattended_patching_last_wednesday.sh <unique alias ID of the Integration created before> >> /tmp/patching-last-wednesday-0300.lst 2>&1

/usr/local/bin/unattended_patching_last_wednesday.sh

#!/bin/bash

[ -z "$1" ] && echo "No argument supplied" && exit 0

current_date=$(/usr/bin/date +%d-%m-%Y)
current_day=$(/usr/bin/date +%d)
current_month=$(/usr/bin/date +%m)
current_year=$(/usr/bin/date +%Y)

last_wednesday=$(ncal -m $current_month | awk '/We/{print $6}')

if [[ $(ncal -m $current_month | awk '/We/{print $6}' | wc -c) -eq 1 ]]; then
    last_wednesday=$(ncal -m $current_month | awk '/We/{print $5}')
fi

if [ "$current_day" -eq "$last_wednesday" ]; then
        /usr/bin/curl --header "X-Custom-Header: semaphoreisamazing" -k https://<your semaphore instance>/api/integrations/$1
    echo "$current_data - Script executed successfully."
else
    echo "$current_date - Nothing to do, the script will be executed on $last_wednesday-$current_month-$current_year."
fi

Hope this can help fixing the issue in someway :)

bmcatherasoo commented 2 months ago

I currently have a different workaround for my playbooks. I added the following tasks inside the playbooks, which need to be triggered only every third Monday and Tuesday of the Month. The Semaphore schedule triggers them every Monday and Tuesday, but if the conditions defined in the playbook are not met, all jobs are skipped.

   - name: Set default values for variables
      ansible.builtin.set_fact:
        custom_schedule_enabled: "{{ custom_schedule_enabled | default(false) }}"
        schedule_type: "{{ schedule_type | default('') }}"

    - name: Set default run_playbook to true if custom scheduling is not enabled
      ansible.builtin.set_fact:
        run_playbook: "{{ not custom_schedule_enabled }}"
      when: custom_schedule_enabled is defined

    - name: Determine if custom scheduling is enabled
      ansible.builtin.set_fact:
        run_playbook: false
      when: custom_schedule_enabled and custom_schedule_enabled

    - name: Check if today is the third Monday of the month
      ansible.builtin.set_fact:
        run_playbook: "{{ (ansible_date_time.weekday == 'Monday' and (ansible_date_time.day | int) >= 15 and (ansible_date_time.day | int) <= 21) }}"
      when: custom_schedule_enabled and schedule_type == "third_monday"

    - name: Check if today is the third Tuesday of the month
      ansible.builtin.set_fact:
        run_playbook: "{{ (ansible_date_time.weekday == 'Tuesday' and (ansible_date_time.day | int) >= 15 and (ansible_date_time.day | int) <= 21) }}"
      when: custom_schedule_enabled and schedule_type == "third_tuesday"

I added this to the schedule for the last Sunday of the month::

   - name: Determine if custom scheduling is enabled
      ansible.builtin.set_fact:
        run_playbook: false
      when: sunday_schedule_enabled is defined and sunday_schedule_enabled

    - name: Check if today is the last Sunday of the month
      ansible.builtin.set_fact:
        run_playbook: "{{ (ansible_date_time.weekday == 'Sunday' and (ansible_date_time.day | int) >= 25) }}"
      when: sunday_schedule_enabled and schedule_type == "last_sunday"

And under each task i added the following condition when: run_playbook

Inside the Inventories which use the custom Schedule I added the following Variable

[all:vars]
custom_schedule_enabled=true
schedule_type=third_monday
Ken5998 commented 2 months ago

I currently have a different workaround for my playbooks. I added the following tasks inside the playbooks, which need to be triggered only every third Monday and Tuesday of the Month. The Semaphore schedule triggers them every Monday and Tuesday, but if the conditions defined in the playbook are not met, all jobs are skipped.

   - name: Set default values for variables
      ansible.builtin.set_fact:
        custom_schedule_enabled: "{{ custom_schedule_enabled | default(false) }}"
        schedule_type: "{{ schedule_type | default('') }}"

    - name: Set default run_playbook to true if custom scheduling is not enabled
      ansible.builtin.set_fact:
        run_playbook: "{{ not custom_schedule_enabled }}"
      when: custom_schedule_enabled is defined

    - name: Determine if custom scheduling is enabled
      ansible.builtin.set_fact:
        run_playbook: false
      when: custom_schedule_enabled and custom_schedule_enabled

    - name: Check if today is the third Monday of the month
      ansible.builtin.set_fact:
        run_playbook: "{{ (ansible_date_time.weekday == 'Monday' and (ansible_date_time.day | int) >= 15 and (ansible_date_time.day | int) <= 21) }}"
      when: custom_schedule_enabled and schedule_type == "third_monday"

    - name: Check if today is the third Tuesday of the month
      ansible.builtin.set_fact:
        run_playbook: "{{ (ansible_date_time.weekday == 'Tuesday' and (ansible_date_time.day | int) >= 15 and (ansible_date_time.day | int) <= 21) }}"
      when: custom_schedule_enabled and schedule_type == "third_tuesday"

I added this to the schedule for the last Sunday of the month::

   - name: Determine if custom scheduling is enabled
      ansible.builtin.set_fact:
        run_playbook: false
      when: sunday_schedule_enabled is defined and sunday_schedule_enabled

    - name: Check if today is the last Sunday of the month
      ansible.builtin.set_fact:
        run_playbook: "{{ (ansible_date_time.weekday == 'Sunday' and (ansible_date_time.day | int) >= 25) }}"
      when: sunday_schedule_enabled and schedule_type == "last_sunday"

And under each task i added the following condition when: run_playbook

Inside the Inventories which use the custom Schedule I added the following Variable

[all:vars]
custom_schedule_enabled=true
schedule_type=third_monday

thanks for sharing your workaround, I also wanted to try it but for laziness I haven't implemented it yet... we have a lot of tasks and roles and this means that I have to add the condition almost everywhere :)