add curl_scheduled role

This commit is contained in:
Sergey Malyuk
2025-12-16 12:24:14 +03:00
parent 64197142db
commit 400834cc3b
21 changed files with 365 additions and 0 deletions

View File

@@ -0,0 +1,16 @@
---
profile: production
strict: true
# Enable checking of loop variable prefixes in roles
loop_var_prefix: "^(__|{role}_)"
skip_list:
- var-naming[no-role-prefix]
warn_list:
- role-name[path]
- var-naming[no-role-prefix]
exclude_paths:
- .github/

2
roles/curl_scheduled/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.vscode
.idea

View File

@@ -0,0 +1,8 @@
---
rules:
brackets:
forbid: false
min-spaces-inside: 0
max-spaces-inside: 2
min-spaces-inside-empty: -1
max-spaces-inside-empty: 2

View File

@@ -0,0 +1,41 @@
curl-scheduled
=========
Configure curl to run on schedule by deploying a systemd service + timer. Useful for sending heartbeats.
Requirements
------------
None
Role Variables
--------------
- `args`: arguments to the curl command
- `url`: address to be accessed by curl
- `schedule`: string compatible with systemd timer `OnSchedule` option (default: `minutely`)
Dependencies
------------
None
Example Playbook
----------------
See `molecule/default/converge.yml`.
License
-------
BSD
Author Information
------------------
msayganova@genlab.llc
corvus-migratorius@proton.me

View File

@@ -0,0 +1,11 @@
---
name: ansible-curl-scheduled
channels:
- conda-forge
dependencies:
- python~=3.12.0
- pip>=24.2
- actionlint
- pip:
- -r requirements.txt
- -r requirements.ci.txt

View File

@@ -0,0 +1,9 @@
---
name: ansible-curl-scheduled
channels:
- conda-forge
dependencies:
- python~=3.12.0
- pip>=24.2
- pip:
- -r requirements.txt

View File

@@ -0,0 +1,4 @@
---
default_curl_cmd: "/usr/bin/curl"
default_curl_args: "-fsS -m 10"
default_schedule: "minutely"

View File

@@ -0,0 +1 @@
---

View File

@@ -0,0 +1,17 @@
---
galaxy_info:
role_name: curl_scheduled
namespace: genlab
author: "Alexander Gorelyshev"
company: "Genlab, LLC"
description: ""
license: "MIT"
min_ansible_version: "2.1"
platforms:
- name: "Ubuntu"
versions: [ "focal", "jammy", "noble" ]
galaxy_tags: [ ]
dependencies: []

View File

@@ -0,0 +1,45 @@
---
- name: Converge
hosts: all
pre_tasks:
- name: "Create test directory"
ansible.builtin.file:
path: "/test"
state: directory
mode: "0664"
- name: "Create a test file"
ansible.builtin.lineinfile:
path: "/test/index.html"
create: true
mode: "0664"
line: "OK"
- name: "Simulate remote HTTP server(s) directly on localhost"
changed_when: false
async: 1
poll: 0
args:
chdir: "/test"
loop:
- 8080
- 8081
- 8082
ansible.builtin.shell:
cmd: nohup python3 -m http.server {{ item }} </dev/null >/dev/null 2>&1 &
executable: /bin/bash
roles:
- role: genlab.curl_scheduled
services:
- label: "localhost-test-zero"
url: "http://127.0.0.1:8080"
schedule: minutely
- label: "localhost-test-one"
url: "http://127.0.0.1:8081"
schedule: hourly
- label: "localhost-test-chained-curl"
curl_cmd: '/usr/bin/curl "http://127.0.0.1:8081" && /usr/bin/curl'
url: "http://127.0.0.1:8082"
schedule: minutely

View File

@@ -0,0 +1,27 @@
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: ubuntu
image: geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu2404}-ansible:latest
pre_build_image: true
command: ${MOLECULE_DOCKER_COMMAND:-""}
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
cgroupns_mode: host
privileged: true
provisioner:
name: ansible
verifier:
name: ansible
lint: |
set -e
yamllint .
ansible-lint .

View File

@@ -0,0 +1,81 @@
---
- name: Verify
hosts: all
gather_facts: false
tasks:
# Verify the systemd timers
- name: "Check the timer status - localhost-test-zero"
register: timer_zero
ansible.builtin.systemd:
name: "curl-localhost-test-zero.timer"
- name: "Assert that the localhost-test-zero timer is running"
ansible.builtin.assert:
that:
- timer_zero.status.ActiveState == "active"
success_msg: "Timer is running"
fail_msg: "Unexpected timer state: '{{ timer_zero.status.ActiveState }}'"
- name: "Check the timer status - localhost-test-one"
register: timer_one
ansible.builtin.systemd:
name: "curl-localhost-test-one.timer"
- name: "Assert that the localhost-test-one timer is running"
ansible.builtin.assert:
that:
- timer_one.status.ActiveState == "active"
success_msg: "Timer is running"
fail_msg: "Unexpected timer state: '{{ timer_one.status.ActiveState }}'"
- name: "Check the timer status - localhost-test-chained-curl"
register: timer_chained_curl
ansible.builtin.systemd:
name: "curl-localhost-test-chained-curl.timer"
- name: "Assert that the localhost-test-chained-curl timer is running"
ansible.builtin.assert:
that:
- timer_chained_curl.status.ActiveState == "active"
success_msg: "Timer is running"
fail_msg: "Unexpected timer state: '{{ timer_chained_curl.status.ActiveState }}'"
## Verify the systemd services
- name: "Check the service status - zero"
register: service_zero
ansible.builtin.systemd:
name: "curl-localhost-test-zero.service"
- name: "Assert that the localhost-test-zero service exited with a 0/SUCCESS status"
ansible.builtin.assert:
that:
- 'service_zero.status.ExecMainStatus == "0"'
success_msg: "Service has exited with a 0/SUCCESS status"
fail_msg: "Unexpected service status code: '{{ service_zero.status.ExecMainStatus }}'"
- name: "Check the service status - one"
register: service_one
ansible.builtin.systemd:
name: "curl-localhost-test-one.service"
- name: "Assert that the localhost-test-one service exited with a 0/SUCCESS status"
ansible.builtin.assert:
that:
- 'service_one.status.ExecMainStatus == "0"'
success_msg: "Service has exited with a 0/SUCCESS status"
fail_msg: "Unexpected service status code: '{{ service_one.status.ExecMainStatus }}'"
- name: "Check the service status - localhost-test-chained-curl"
register: service_chained_curl
ansible.builtin.systemd:
name: "curl-localhost-test-chained-curl.service"
- name: "Assert that the localhost-test-chained-curl service exited with a 0/SUCCESS status"
ansible.builtin.assert:
that:
- 'service_chained_curl.status.ExecMainStatus == "0"'
success_msg: "Service has exited with a 0/SUCCESS status"
fail_msg: "Unexpected service status code: '{{ service_chained_curl.status.ExecMainStatus }}'"

View File

@@ -0,0 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
]
}

View File

@@ -0,0 +1,6 @@
ansible-lint
molecule==24.12.0
molecule-plugins[docker]
docker~=7.1.0
requests==2.31.0 # pinned to the latest version not breaking Docker SDK
yamllint

View File

@@ -0,0 +1 @@
ansible~=11.1.0

View File

@@ -0,0 +1,3 @@
# requirements file
---
collections: []

View File

@@ -0,0 +1,33 @@
---
- name: "Deploy-Service | Create systemd service file: '{{ job.label }}'"
vars:
label: "{{ job.label }}"
url: "{{ job.url }}"
curl_cmd: "{{ job.curl_cmd | default(default_curl_cmd) }}"
curl_args: "{{ job.curl_args | default(default_curl_args) }}"
register: service
ansible.builtin.template:
src: "placeholder.service"
dest: "/etc/systemd/system/curl-{{ job.label }}.service"
mode: "0660"
validate: systemd-analyze verify %s
- name: "Deploy-Service | Create systemd timer file: '{{ job.label }}'"
vars:
label: "{{ job.label }}"
schedule: "{{ job.schedule | default(default_schedule) }}"
register: timer
ansible.builtin.template:
src: "placeholder.timer"
dest: "/etc/systemd/system/curl-{{ job.label }}.timer"
mode: "0660"
validate: systemd-analyze verify %s
- name: "Deploy-Service | Enable and start the timer: '{{ job.label }}'" # noqa: no-handler
become: true
when: service.changed or timer.changed
ansible.builtin.systemd:
name: "curl-{{ job.label }}.timer"
state: started
enabled: true
daemon_reload: true

View File

@@ -0,0 +1,19 @@
---
- name: "Install curl (Debian derivatives)"
when: ansible_os_family == "Debian"
ansible.builtin.apt:
name: curl
state: present
update_cache: true
- name: "Install curl (RHEL derivatives)"
when: ansible_os_family == "RedHat"
ansible.builtin.dnf:
name: curl
state: present
- name: "Configure and deploy systemd service"
loop: "{{ services }}"
loop_control:
loop_var: "job"
ansible.builtin.include_tasks: "deploy-service.yml"

View File

@@ -0,0 +1,21 @@
[Unit]
Description=Run an HTTP request via curl designated '{{ label }}'
After=network.target
[Service]
Type=oneshot
ExecStart={{ curl_cmd }} {{ curl_args }} "{{ url }}"
Restart=no
# Security hardening
ProtectSystem=strict
NoNewPrivileges=true
PrivateTmp=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectKernelTunables=true
ProtectClock=yes
RestrictSUIDSGID=true
[Install]
WantedBy=multi-user.targer

View File

@@ -0,0 +1,12 @@
[Unit]
Description=Trigger a curl command designated '{{ label }}'
Requires=curl-{{ label }}.service
[Timer]
Unit=curl-{{ label }}.service
OnCalendar={{ schedule }}
AccuracySec=1m
Persistent=true
[Install]
WantedBy=timers.target

View File

@@ -0,0 +1,2 @@
---
kuma_port: "3001"