Implemented role System Maintenance Service Freezer

This commit is contained in:
Kevin Veen-Birkenbach 2023-12-13 19:02:07 +01:00
parent 58c70659cf
commit 518b98cfd1
8 changed files with 138 additions and 0 deletions

View File

@ -67,6 +67,17 @@ version_mailu: "2.0"
version_akaunting: "latest"
version_mastodon: "latest"
# Services which modify the system:
system_maintenance_services:
- "backup-docker-to-local"
- "backup-remote-to-local"
- "backup-data-to-usb"
- "cleanup-backups"
- "cleanup-disc-space"
- "cleanup-failed-docker-backups"
- "heal-docker"
- "update-docker"
# Routings
redirect_domain_mappings:
- { source: "nextcloud.{{top_domain}}", target: "cloud.{{top_domain}}" }

View File

@ -0,0 +1,16 @@
# System Maintenance Service Freezer
## Overview
This Ansible role is designed to manage system services through freezing (disabling) and defrosting (enabling) actions. It automates the process of managing crucial system services, especially useful for maintenance tasks like backups, cleanups, and updates.
## Role Variables
- `system_maintenance_services`: List of services to be managed by this role.
## Usage
Configure the role by defining the required variables. The role creates systemd service files that control the specified services based on the `freeze` or `defrost` actions.
For further details and usage examples, refer to the chat conversation with ChatGPT: [Link to ChatGPT Conversation](https://chat.openai.com/share/212af169-1b57-41df-bd2d-c3d32eb1331b).
## Dependencies
- `systemd-notifier`: Ensure this role is present for handling service failures.

View File

@ -0,0 +1,71 @@
import argparse
import subprocess
import time
def check_service_active(service_name):
"""Check if a service is active."""
result = subprocess.run(['systemctl', 'is-active', service_name], stdout=subprocess.PIPE)
return result.stdout.decode('utf-8').strip() == 'active'
def service_exists(service_name):
"""Check if a service exists."""
result = subprocess.run(['systemctl', 'status', service_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return result.returncode == 0
def freeze(services_to_wait_for, ignored_services):
# Filter services that exist and are not in the ignored list
active_services = [service for service in services_to_wait_for if service_exists(service) and service not in ignored_services]
while active_services:
for service in active_services:
if not check_service_active(service):
print(f"{service} stopped.")
# Disable the service
subprocess.run(['systemctl', 'disable', service])
print(f"{service} disabled.")
# Stop and disable the corresponding timer, if it exists
timer_name = service + ".timer"
timer_check = subprocess.run(['systemctl', 'list-timers', '--all', timer_name], stdout=subprocess.PIPE)
if timer_name in timer_check.stdout.decode():
subprocess.run(['systemctl', 'stop', timer_name])
subprocess.run(['systemctl', 'disable', timer_name])
print(f"{timer_name} stopped and disabled.")
active_services.remove(service)
else:
print(f"Waiting for {service} to stop...")
time.sleep(5)
print("All required services have stopped.")
def defrost(services_to_wait_for, ignored_services):
for service in services_to_wait_for:
if service not in ignored_services and service_exists(service):
# Enable the service
subprocess.run(['systemctl', 'enable', service])
print(f"{service} enabled.")
# Start and enable the corresponding timer, if it exists
timer_name = service + ".timer"
timer_check = subprocess.run(['systemctl', 'list-timers', '--all', timer_name], stdout=subprocess.PIPE)
if timer_name in timer_check.stdout.decode():
subprocess.run(['systemctl', 'start', timer_name])
subprocess.run(['systemctl', 'enable', timer_name])
print(f"{timer_name} started and enabled.")
def main(services_to_wait_for, ignored_services, action):
if action == 'freeze':
# Code to handle freeze action
freeze(services_to_wait_for, ignored_services)
elif action == 'defrost':
defrost(services_to_wait_for, ignored_services)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='freezes and defrost systemctl services and timers')
parser.add_argument('action', choices=['freeze', 'defrost'], help='Action to perform: freeze or defrost services.')
parser.add_argument('services', help='Comma-separated list of services to apply the action to')
parser.add_argument('--ignore', help='Comma-separated list of services to ignore in the action', default='')
args = parser.parse_args()
services_to_wait_for = args.services.split(',')
ignored_services = args.ignore.split(',') if args.ignore else []
main(services_to_wait_for, ignored_services,args.action)

View File

@ -0,0 +1,9 @@
- name: "restart system-maintenance-service-freeze.service"
systemd:
name: system-maintenance-service-freeze.service
daemon_reload: yes
- name: "restart system-maintenance-service-defrost.service"
systemd:
name: system-maintenance-service-defrost.service
daemon_reload: yes

View File

@ -0,0 +1,3 @@
---
dependencies:
- role: systemd-notifier

View File

@ -0,0 +1,20 @@
---
- name: create {{freezer_script}}
copy:
src: system-maintenance-service-freezer.py
dest: "{{freezer_script}}"
- name: Configure system-maintenance-service for each action
loop:
- freeze
- defrost
template:
src: system-maintenance-service-freezer.service.j2
dest: "/etc/systemd/system/system-maintenance-service-{{ item }}.service"
notify: "restart system-maintenance-service-{{ item }} service"
when: run_once_systemd_freezer is not defined
- name: run the system_maintenance_service_freezer tasks once
set_fact:
run_once_systemd_freezer: true
when: run_once_systemd_freezer is not defined

View File

@ -0,0 +1,7 @@
[Unit]
Description={{item}} systemctl maintanance services
OnFailure=systemd-notifier@%n.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c '/usr/bin/python {{ freezer_script }} {{item}} {{ system_maintenance_services | join(",") }}'

View File

@ -0,0 +1 @@
freezer_script: "{{path_administrator_scripts}}system-maintenance-service-freezer.py"