From e59fc5f9a860447b29124b9a822d91bf19b2f94d Mon Sep 17 00:00:00 2001 From: Max Mehl Date: Thu, 3 Apr 2025 14:44:21 +0200 Subject: [PATCH] initial commit of role --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++ defaults/main.yml | 8 +++++ tasks/main.yml | 68 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 README.md create mode 100644 defaults/main.yml create mode 100644 tasks/main.yml diff --git a/README.md b/README.md new file mode 100644 index 0000000..34ad54d --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ + + +# Ansible role for creating users systemd services + +[![REUSE status](https://api.reuse.software/badge/src.mehl.mx/mxmehl/ansible-role-systemd-user)](https://api.reuse.software/info/src.mehl.mx/mxmehl/ansible-role-systemd-user) + +This Ansible role allows for easy and painless creation of systemd services for a user running only with this user's privileges. + +## Requirements + +* Debian and `apt` +* `python3` + +## Installation + +Add this role as a submodule: `git submodule add https://src.mehl.mx/mxmehl/ansible-role-systemd-user.git roles/systemd-user` + +## Usage and examples + +### Basic + +The example below will add, enable and start `my-daemon.service` for the user `user1`. It expects the existence of a template file `my-daemon.service.j2` reachable for this role. + +```yaml +- name: Setup systemd user service + include_role: + name: systemd-user # name of the role on your system + vars: + # Name of the user you want to create the service for + user: "user1" + # Name of the service + service: my-daemon +``` + +### Custom template / file + +The following example does the same as before, but allows you to use an own template. The effective service file will still be `my-daemon.service`. + +Alternatively, you can just copy the service file using the `copy_file` variable. + +```yaml +- name: Setup systemd user service + include_role: + name: systemd-user # name of the role on your system + vars: + user: "user1" + service: my-daemon + # Use customservice.j2 as template + template: customservice.j2 + # Use my-service.service as local file that shall be used as service file + # copy_file: my-service.service +``` + +### Define state of service + +By default, the role reloads the user's systemd daemon and starts and enables the new service. You can configure that: + +```yaml +- name: Setup systemd user service + include_role: + name: systemd-user # name of the role on your system + vars: + user: "user1" + service: my-daemon + # Service shall be stopped, disabled, and the systemd daemon not reloaded + systemd_state: stopped + systemd_enabled: false + systemd_daemon_reload: false +``` + +## License + +Apache-2.0, Copyright Max Mehl diff --git a/defaults/main.yml b/defaults/main.yml new file mode 100644 index 0000000..b3e4e84 --- /dev/null +++ b/defaults/main.yml @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: 2025 Max Mehl +# +# SPDX-License-Identifier: Apache-2.0 + +--- +systemd_state: started +systemd_enabled: true +systemd_daemon_reload: true diff --git a/tasks/main.yml b/tasks/main.yml new file mode 100644 index 0000000..1df28a1 --- /dev/null +++ b/tasks/main.yml @@ -0,0 +1,68 @@ +# SPDX-FileCopyrightText: 2025 Max Mehl +# +# SPDX-License-Identifier: Apache-2.0 + +--- +- name: Set template file name + ansible.builtin.set_fact: + template: "{{ service }}.service.j2" + when: template is not defined + +- name: Install required dependencies + ansible.builtin.apt: + pkg: + - systemd-container # necessary to use machinectl become_method + install_recommends: false + +- name: Register user info of {{ user }} + ansible.builtin.user: + name: "{{ user }}" + check_mode: true + register: user_info + +- name: Ensure user systemd directory exists + ansible.builtin.file: + path: "{{ user_info.home }}/.config/systemd/user/" + state: directory + mode: "0755" + owner: "{{ user }}" + group: "{{ user }}" + +- name: Ensure systemd service file is present (template) + ansible.builtin.template: + src: "{{ template }}" + dest: "{{ user_info.home }}/.config/systemd/user/{{ service }}.service" + mode: "0644" + owner: "{{ user }}" + group: "{{ user }}" + when: copy_file is not defined + +- name: Ensure systemd service file is present (copy) + ansible.builtin.copy: + src: "{{ copy_file }}" + dest: "{{ user_info.home }}/.config/systemd/user/{{ service }}.service" + mode: "0644" + owner: "{{ user }}" + group: "{{ user }}" + when: copy_file is defined + +- name: "Check whether user is lingering: {{ user }}" + ansible.builtin.stat: + path: "/var/lib/systemd/linger/{{ user }}" + register: user_lingering + +- name: Ensure systemd lingering is enabled for user {{ user }} + ansible.builtin.command: loginctl enable-linger {{ user }} + changed_when: false + when: not user_lingering.stat.exists + +- name: Ensure systemd service is running and enabled + ansible.builtin.systemd_service: + name: "{{ service }}" + state: "{{ systemd_state }}" + enabled: "{{ systemd_enabled }}" + daemon_reload: "{{ systemd_daemon_reload }}" + scope: user + become: true + become_user: "{{ user }}" + become_method: community.general.machinectl # in order to get XDG_RUNTIME_DIR and user's DBUS session