From 7745439f35426c60b9e53eae377c0e38e2ec4cb2 Mon Sep 17 00:00:00 2001 From: Kevin Carter Date: Wed, 21 Mar 2018 12:39:38 -0500 Subject: [PATCH] Add tests to the service role * Document the optionality in the defaults * validate the input in the tasks before it's templated * Standardize on the exec(starts,stops,reloads} interface * Update the readme * Add functional test Change-Id: Icae36f970178b1cc79d069a94321afb1732a8c5c Signed-off-by: Kevin Carter --- README.md | 84 +---------------------- defaults/main.yml | 56 +++++++-------- examples/playbook.yml | 7 +- html-docs/index.html | 14 ++-- tasks/main.yml | 96 +++++++++++++++++++------- templates/systemd-service.j2 | 6 +- templates/systemd-tmpfiles-lock.j2 | 3 - templates/systemd-tmpfiles.j2 | 7 +- tests/test.yml | 106 +++++++++++++++++++++++++++++ vars/main.yml | 21 ------ 10 files changed, 228 insertions(+), 172 deletions(-) delete mode 100644 templates/systemd-tmpfiles-lock.j2 delete mode 100644 vars/main.yml diff --git a/README.md b/README.md index 5001d4f..c50f047 100644 --- a/README.md +++ b/README.md @@ -18,84 +18,6 @@ You can also use the ``ansible-galaxy`` command on the ``ansible-role-requiremen ---- -###### Defaults (See actual role for more details) - -``` yaml -# This is the default path for a given service. Set this for general service lookups or -# define "program_override" option in the systemd_services dictionary. -systemd_bin_path: /usr/local/bin - -systemd_user_name: root -systemd_group_name: root -systemd_slice_name: system -systemd_lock_path: /var/lock - -# This is the prefix used for all temp files of a given type. -systemd_tempd_prefix: tempd - -# Give a reasonable amount of time for the server to start up/shut down -systemd_TimeoutSec: 120 -systemd_Restart: on-failure -systemd_RestartSec: 2 - -# Accounting options -systemd_CPUAccounting: true -systemd_BlockIOAccounting: true -systemd_MemoryAccounting: true -systemd_TasksAccounting: true - -# Sandboxing options -systemd_PrivateTmp: true -systemd_PrivateDevices: false -systemd_PrivateNetwork: true -systemd_PrivateUsers: true - -# Start service after a given target. This is here because we want to define common -# after targets used on most services. This can be overridden or agumented using -# the "systemd_services" dictionary option "init_config_overrides". -systemd_after_targets: - - syslog.target - - network.target - -# Set the service enabled state. Valid options are: [yes, no] -systemd_service_enabled: yes - -# Set global service overrides used within the service unit file. -systemd_service_config_overrides: {} - -# The systemd services dictionary is a set of services that will be created. The dictionary -# can contain the following options: -# `service_name` -- (required) used to define the name of the service. This is typically the name of the executable. -# `init_config_overrides` -- (optional) This allows any section or key=value pair to be set within the systemd unit file. -# `program_config_options` -- (optional) Provides the ability to pass in flags to a given service for execution. -# `program_override` -- (optional) sets the full path to the executable that will be run by the service file. -# `enabled` -- (optional) Set the enabled state of the service. -# `state` -- (optional) Set the running state of the service. - -# Examples: -# systemd_services: -# ServiceW: -# service_name: ServiceW -# init_config_overrides: {} # This is used to add in arbitratry unit file options -# ServiceX: -# service_name: ServiceX -# init_config_overrides: {} # This is used to add in arbitratry unit file options -# program_config_options: '--flag1 things --flag2 other' -# ServiceY: -# service_name: ServiceY -# init_config_overrides: {} # This is used to add in arbitratry unit file options -# program_override: '/usr/bin/ServiceY' -# ServiceZ: -# service_name: ServiceZ -# init_config_overrides: {} # This is used to add in arbitratry unit file options -# enabled: no -# state: stopped - -systemd_services: {} -``` - ----- - ###### Example playbook ``` yaml @@ -105,9 +27,9 @@ systemd_services: {} roles: - role: "systemd_service" systemd_services: - service_name: ServiceX - init_config_overrides: {} - program_config_options: '--flag1 things --flag2 other' + - service_name: ServiceX + execstarts: + - /path/ServiceX --flag1 tags: - servicex-init diff --git a/defaults/main.yml b/defaults/main.yml index fd093cf..03b78bc 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -13,14 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This is the default path for a given service. Set this for general service lookups or -# define "program_override" option in the systemd_services dictionary. -systemd_bin_path: /usr/local/bin - systemd_user_name: root systemd_group_name: root systemd_slice_name: system -systemd_lock_path: /var/lock # This is the prefix used for all temp files of a given type. systemd_tempd_prefix: tempd @@ -44,7 +39,7 @@ systemd_PrivateUsers: true # Start service after a given target. This is here because we want to define common # after targets used on most services. This can be overridden or agumented using -# the "systemd_services" dictionary option "init_config_overrides". +# the "systemd_services" dictionary option "config_overrides". systemd_after_targets: - syslog.target - network.target @@ -62,41 +57,48 @@ systemd_default_service_type: simple # The systemd services dictionary is a set of services that will be created. The dictionary # can contain the following options: # `service_name` -- (required) used to define the name of the service. This is typically the name of the executable. -# `init_config_overrides` -- (optional) This allows any section or key=value pair to be set within the systemd unit file. -# `program_config_options` -- (optional) Provides the ability to pass in flags to a given service for execution. -# `program_override` -- (optional) sets the full path to the executable that will be run by the service file. +# `service_type` -- (optional) Set the service type, default is "simple". +# `execstarts` -- (required) Set the program to start, when the service is simple the list has a max length of 1. +# `execstops` -- (optional) Set the program to stop, when the service is simple the list has a max length of 1. +# `config_overrides` -- (optional) This allows any section or key=value pair to be set within the systemd unit file. +# `program_sandboxing` -- (optional) Case sensitive Key=Value pairs for service Sandboxing +# `program_accounting` -- (optional) Case sensitive Key=Value pairs for service Accounting # `enabled` -- (optional) Set the enabled state of the service. # `state` -- (optional) Set the running state of the service. # Examples: # systemd_services: -# ServiceW: -# service_name: ServiceW -# init_config_overrides: {} # This is used to add in arbitratry unit file options -# ServiceX: -# service_name: ServiceX -# init_config_overrides: {} # This is used to add in arbitratry unit file options -# program_config_options: '--flag1 things --flag2 other' +# - service_name: ServiceW +# config_overrides: {} # This is used to add in arbitratry unit file options +# execstarts: +# - ServiceW +# +# - service_name: ServiceX +# config_overrides: {} # This is used to add in arbitratry unit file options +# execstarts: +# - ServiceX # program_sandboxing: # PrivateTmp: true # program_accounting: # CPUAccounting: true -# ServiceY: -# service_name: ServiceY -# init_config_overrides: {} # This is used to add in arbitratry unit file options -# program_override: '/usr/bin/ServiceY' -# program_stop: '/usr/bin/stopcmd' -# ServiceZ: -# service_name: ServiceZ -# init_config_overrides: {} # This is used to add in arbitratry unit file options +# +# - service_name: ServiceY +# config_overrides: {} # This is used to add in arbitratry unit file options +# execstarts: +# - '/usr/bin/ServiceY' +# execstarts: +# - '/usr/bin/stopcmd' +# +# - service_name: ServiceZ +# config_overrides: {} # This is used to add in arbitratry unit file options # enabled: no # state: stopped # service_type: oneshot -# program_execstarts: +# execstarts: # - /usr/bin/startcmd1 # - /usr/bin/startcmd2 -# program_execstops +# execstops # - /usr/bin/stopcmd1 # - /usr/bin/stopcmd2 -systemd_services: {} +systemd_services: [] diff --git a/examples/playbook.yml b/examples/playbook.yml index c287b6f..02a6cd5 100644 --- a/examples/playbook.yml +++ b/examples/playbook.yml @@ -6,8 +6,5 @@ roles: - role: "systemd_service" systemd_services: - service_name: ServiceX - init_config_overrides: {} - program_config_options: '--flag1 things --flag2 other' - tags: - - servicex-init + - service_name: ServiceX + config_overrides: {} diff --git a/html-docs/index.html b/html-docs/index.html index f3a48fc..8277982 100644 --- a/html-docs/index.html +++ b/html-docs/index.html @@ -253,7 +253,7 @@ ga('send', 'pageview'); # Start service after a given target. This is here because we want to define common # after targets used on most services. This can be overridden or agumented using -# the "systemd_services" dictionary option "init_config_overrides". +# the "systemd_services" dictionary option "config_overrides". systemd_after_targets: - syslog.target - network.target @@ -267,7 +267,7 @@ ga('send', 'pageview'); # The systemd services dictionary is a set of services that will be created. The dictionary # can contain the following options: # `service_name` -- (required) used to define the name of the service. This is typically the name of the executable. -# `init_config_overrides` -- (optional) This allows any section or key=value pair to be set within the systemd unit file. +# `config_overrides` -- (optional) This allows any section or key=value pair to be set within the systemd unit file. # `program_config_options` -- (optional) Provides the ability to pass in flags to a given service for execution. # `program_override` -- (optional) sets the full path to the executable that will be run by the service file. # `enabled` -- (optional) Set the enabled state of the service. @@ -277,18 +277,18 @@ ga('send', 'pageview'); # systemd_services: # ServiceW: # service_name: ServiceW -# init_config_overrides: {} # This is used to add in arbitratry unit file options +# config_overrides: {} # This is used to add in arbitratry unit file options # ServiceX: # service_name: ServiceX -# init_config_overrides: {} # This is used to add in arbitratry unit file options +# config_overrides: {} # This is used to add in arbitratry unit file options # program_config_options: '--flag1 things --flag2 other' # ServiceY: # service_name: ServiceY -# init_config_overrides: {} # This is used to add in arbitratry unit file options +# config_overrides: {} # This is used to add in arbitratry unit file options # program_override: '/usr/bin/ServiceY' # ServiceZ: # service_name: ServiceZ -# init_config_overrides: {} # This is used to add in arbitratry unit file options +# config_overrides: {} # This is used to add in arbitratry unit file options # enabled: no # state: stopped @@ -307,7 +307,7 @@ ga('send', 'pageview'); - role: "systemd_service" systemd_services: service_name: ServiceX - init_config_overrides: {} + config_overrides: {} program_config_options: '--flag1 things --flag2 other' tags: - servicex-init diff --git a/tasks/main.yml b/tasks/main.yml index d125f25..ab28b42 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -15,66 +15,116 @@ - name: Create TEMP run dir file: - path: "/var/run/{{ item.service_name }}" + path: "/var/run/{{ item.service_name | replace(' ', '_') }}" state: directory - owner: "{{ systemd_user_name }}" - group: "{{ systemd_group_name }}" + owner: "{{ item.systemd_user_name | default(systemd_user_name) }}" + group: "{{ item.systemd_group_name | default(systemd_group_name) }}" mode: "02755" with_items: "{{ systemd_services }}" tags: - systemd-init -- name: Create TEMP lock dir +- name: Create TEMP service lock dir file: - path: "/var/lock/{{ item.service_name }}" + path: "/var/lock/{{ item.service_name | replace(' ', '_') }}" state: directory - owner: "{{ systemd_user_name }}" - group: "{{ systemd_group_name }}" + owner: "{{ item.systemd_user_name | default(systemd_user_name) }}" + group: "{{ item.systemd_group_name | default(systemd_group_name) }}" mode: "02755" with_items: "{{ systemd_services }}" tags: - systemd-init +- name: Create TEMP defined lock dir + file: + path: "{{ item.systemd_lock_path }}" + state: directory + owner: "{{ item.systemd_user_name | default(systemd_user_name) }}" + group: "{{ item.systemd_group_name | default(systemd_group_name) }}" + mode: "02755" + when: + - item.systemd_lock_path is defined + with_items: "{{ systemd_services }}" + tags: + - systemd-service + - name: Create tmpfiles.d entry template: src: "systemd-tmpfiles.j2" - dest: "/etc/tmpfiles.d/{{ systemd_tempd_prefix }}-{{ item.service_name }}.conf" + dest: "/etc/tmpfiles.d/{{ item.systemd_tempd_prefix | default(systemd_tempd_prefix) }}-{{ item.service_name | replace(' ', '_') }}.conf" mode: "0644" owner: "root" group: "root" + when: + - item.systemd_lock_path is defined with_items: "{{ systemd_services }}" tags: - - systemd-init + - systemd-service -- name: Create tmpfiles.d entry - template: - src: "systemd-tmpfiles-lock.j2" - dest: "/etc/tmpfiles.d/{{ systemd_tempd_prefix }}-{{ systemd_lock_path.strip('/') | replace('/', '-') }}-lock.conf" - mode: "0644" - owner: "root" - group: "root" +- name: Check ExecStarts + fail: + msg: >- + When the service type is "simple" only ONE command can be started. Check + The list of execstarts and limit it to a single command per service or + consider using the "oneshot" service type. Defined ExecStart commands + "{{ item.execstarts }}". + when: + - item.execstarts is not string + - item.execstarts | length > 1 + - item.service_type | default(systemd_default_service_type) != 'oneshot' + with_items: "{{ systemd_services }}" tags: - - systemd-init + - systemd-service -- name: Place the systemd init script +- name: Check ExecStops + fail: + msg: >- + When the service type is "simple" only ONE command can be stopped. Check + The list of execstops and limit it to a single command per service or + consider using the "oneshot" service type. Defined ExecStop commands + "{{ item.execstops }}". + when: + - item.execstops is not string + - item.execstops | default([]) | length > 1 + - item.service_type | default(systemd_default_service_type) != 'oneshot' + with_items: "{{ systemd_services }}" + tags: + - systemd-service + +- name: Check ExecReloads + fail: + msg: >- + When the service type is "simple" only ONE command can be reloaded. Check + The list of execreloads and limit it to a single command per service or + consider using the "oneshot" service type. Defined ExecStop commands + "{{ item.execreloads }}". + when: + - item.execreloads is not string + - item.execreloads | default([]) | length > 1 + - item.service_type | default(systemd_default_service_type) != 'oneshot' + with_items: "{{ systemd_services }}" + tags: + - systemd-service + +- name: Place the systemd service config_template: src: "systemd-service.j2" - dest: "/etc/systemd/system/{{ item.service_name }}.service" + dest: "/etc/systemd/system/{{ item.service_name | replace(' ', '_') }}.service" mode: "0644" owner: "root" group: "root" - config_overrides: "{{ item.init_config_overrides | default(systemd_service_config_overrides) }}" + config_overrides: "{{ item.config_overrides | default(systemd_service_config_overrides) }}" config_type: "ini" with_items: "{{ systemd_services }}" tags: - - systemd-init + - systemd-service - name: Load service systemd: - name: "{{ item.service_name }}" + name: "{{ item.service_name | replace(' ', '_') }}" daemon_reload: yes enabled: "{{ item.enabled | default(systemd_service_enabled) }}" state: "{{ item.state | default(omit) }}" with_items: "{{ systemd_services }}" tags: - - systemd-init + - systemd-service diff --git a/templates/systemd-service.j2 b/templates/systemd-service.j2 index 3f538b6..de3719c 100644 --- a/templates/systemd-service.j2 +++ b/templates/systemd-service.j2 @@ -12,7 +12,7 @@ Type={{ service_type }} User={{ systemd_user_name }} Group={{ systemd_group_name }} -{% set _execstarts = item.execstarts | default(systemd_default_execstarts) %} +{% set _execstarts = item.execstarts %} {% if _execstarts is string %} {% set _execstarts = [_execstarts] %} {% endif %} @@ -20,7 +20,7 @@ Group={{ systemd_group_name }} ExecStart={{ execstart }} {% endfor %} -{% set _execreloads = item.execreloads | default(systemd_default_execreloads) %} +{% set _execreloads = item.execreloads | default((service_type == 'simple') | ternary(['/bin/kill -HUP $MAINPID'], [])) %} {% if _execreloads is string %} {% set _execreloads = [_execreloads] %} {% endif %} @@ -28,7 +28,7 @@ ExecStart={{ execstart }} ExecReload={{ execreload }} {% endfor %} -{% set _execstops = item.execstops | default(systemd_default_execstops) %} +{% set _execstops = item.execstops | default([]) %} {% if _execstops is string %} {% set _execstops = [_execstops] %} {% endif %} diff --git a/templates/systemd-tmpfiles-lock.j2 b/templates/systemd-tmpfiles-lock.j2 deleted file mode 100644 index e570245..0000000 --- a/templates/systemd-tmpfiles-lock.j2 +++ /dev/null @@ -1,3 +0,0 @@ -# {{ ansible_managed }} - -D {{ systemd_lock_path }} 2755 {{ systemd_user_name }} {{ systemd_group_name }} diff --git a/templates/systemd-tmpfiles.j2 b/templates/systemd-tmpfiles.j2 index 11d1ee1..c8388ba 100644 --- a/templates/systemd-tmpfiles.j2 +++ b/templates/systemd-tmpfiles.j2 @@ -1,4 +1,7 @@ # {{ ansible_managed }} -D /var/lock/{{ item.service_name }} 2755 {{ systemd_user_name }} {{ systemd_group_name }} -D /var/run/{{ item.service_name }} 2755 {{ systemd_user_name }} {{ systemd_group_name }} +{% if item.systemd_lock_path is defined %} +D {{ item.systemd_lock_path }} 2755 {{ item.systemd_user_name | default(systemd_user_name) }} {{ item.systemd_group_name | default(systemd_group_name) }} +{% endif %} +D /var/lock/{{ item.service_name | replace(' ', '_') }} 2755 {{ item.systemd_user_name | default(systemd_user_name) }} {{ item.systemd_group_name | default(systemd_group_name) }} +D /var/run/{{ item.service_name | replace(' ', '_') }} 2755 {{ item.systemd_user_name | default(systemd_user_name) }} {{ item.systemd_group_name | default(systemd_group_name) }} diff --git a/tests/test.yml b/tests/test.yml index f30fa88..acdff39 100644 --- a/tests/test.yml +++ b/tests/test.yml @@ -21,3 +21,109 @@ become: true roles: - role: "systemd_service" + systemd_services: + - service_name: "test simple service0" + execstarts: "/bin/bash -c 'while true; do sleep 2 && echo test simple service; done'" + enabled: yes + state: started + - service_name: "test oneshot service0" + config_overrides: + Unit: + Description: Test oneshot service + After: network-online.target + Wants: network-online.target + Service: + RemainAfterExit: yes + service_type: oneshot + execstarts: + - "/bin/bash -c 'echo start1'" + - "/bin/bash -c 'echo start2'" + execstops: + - "/bin/bash -c 'echo stop1'" + - "/bin/bash -c 'echo stop2'" + enabled: yes + state: started + systemd_tempd_prefix: openstack + systemd_lock_path: /var/lock/networking + post_tasks: + - name: Check Services + command: systemctl status "{{ item }}" + changed_when: false + with_items: + - test_simple_service0 + - test_oneshot_service0 + tags: + - skip_ansible_lint + + - name: Test failure condition + block: + - name: Run the systemd service role + include_role: + name: systemd_service + private: true + vars: + systemd_services: + - service_name: "test simple service1" + execstarts: + - "/bin/bash -c 'while true; do sleep 2 && echo test simple service1; done'" + - "/bin/bash -c 'while true; do sleep 2 && echo test simple service2; done'" + rescue: + - name: Set negative service test pass fact + set_fact: + systemd_service_execstarts_test: true + + - name: Test failure condition + block: + - name: Run the systemd service role + include_role: + name: systemd_service + private: true + vars: + systemd_services: + - service_name: "test simple service2" + execstarts: "/bin/bash -c 'while true; do sleep 2 && echo test simple service; done'" + execstops: + - /bin/true + - /bin/true + rescue: + - name: Set negative service test pass fact + set_fact: + systemd_service_execstops_test: true + + - name: Test failure condition + block: + - name: Run the systemd service role + include_role: + name: systemd_service + private: true + vars: + systemd_services: + - service_name: "test simple service3" + execstarts: "/bin/true" + execreloads: + - /bin/true + - /bin/true + rescue: + - name: Set negative service test pass fact + set_fact: + systemd_service_execreloads_test: true + + - name: Check negative service testing + fail: + msg: >- + Failed negative service testing. Results -- + systemd_service_execstarts_test: {{ systemd_service_execstarts_test }}, + systemd_service_execstops_test: {{ systemd_service_execstops_test }}, + systemd_service_execreloads_test: {{ systemd_service_execreloads_test }} + when: + - (not systemd_service_execstarts_test | bool) or + (not systemd_service_execstops_test | bool) or + (not systemd_service_execreloads_test | bool) + + - name: Notify tests passed + debug: + msg: All tests have passed + vars: + systemd_service_execstarts_test: false + systemd_service_execstops_test: false + systemd_service_execreloads_test: false diff --git a/vars/main.yml b/vars/main.yml deleted file mode 100644 index a956d1c..0000000 --- a/vars/main.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# Copyright 2018, Logan Vig -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -systemd_default_execstarts: - - "{{ item.program_override | default(systemd_bin_path ~ '/' ~ item.service_name) }} {{ item.program_config_options | default('') }}" -systemd_default_execreloads: - - '/bin/kill -HUP $MAINPID' -systemd_default_execstops: "{{ item.program_stop | default([]) }}" -