add new sub_state return value to service_facts module#84618
add new sub_state return value to service_facts module#84618NomakCooper wants to merge 0 commit intoansible:develfrom
Conversation
|
added new changelog/fragments |
|
I created a temporary test env to evaluate the module with these changes. # ansible --version
ansible [core 2.18.2]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.11/site-packages/ansible
ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/local/bin/ansible
python version = 3.11.5 (main, Jan 27 2025, 22:17:48) [GCC 11.5.0 20240719 (Red Hat 11.5.0-2)] (/usr/local/bin/python3.11)
jinja version = 3.1.5
libyaml = TrueThis test playbook kills the # systemd_test.yml
- name: Test systemd service_facts
hosts: localhost
gather_facts: no
tasks:
- name: kill rsyslog
command: killall rsyslogd
- name: populate service facts
service_facts:
- name: print rsyslog dict from service_facts
debug:
msg: "{{ ansible_facts['services'].values() | selectattr('name', 'equalto', 'rsyslog.service') }}"results: # ansible-playbook systemd_test.yml
PLAY [Test systemd service_facts] ***********************************************************************************
TASK [kill rsyslog] *************************************************************************************************
changed: [localhost]
TASK [populate service facts] ***************************************************************************************
ok: [localhost]
TASK [print rsyslog dict from service_facts] ************************************************************************
ok: [localhost] => {
"msg": [
{
"name": "rsyslog.service",
"source": "systemd",
"state": "stopped",
"status": "enabled",
"sub_state": "dead"
}
]
}
PLAY RECAP *********************************************************************************************************
localhost : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 |
|
The test The test The test |
|
I have added changes to run integration tests for the
In this new test, the The test uses the already present Scenarios:
In this last test, you can see how the module reports the following values: "ansible_test.service": {
"name": "ansible_test.service",
"source": "systemd",
"state": "stopped",
"status": "enabled",
"sub_state": "exited"
} |
|
I have rewritten the
new tree: |
|
@NomakCooper While you are here, can you please check #76667 changes? Thanks. |
|
@Akasurde I viewed PR #76667, and based on James Livulpi's description, it seems similar to my original idea regarding the Setting aside the fact that the PR is too old,it references an outdated version of While the core idea is valid, I initially considered this approach as well. I quickly tested my updated version of the module in my test environment ( # systemctl list-units auto-cpufreq.service --no-pager --type service --all --plain
UNIT LOAD ACTIVE SUB DESCRIPTION
auto-cpufreq.service not-found inactive dead auto-cpufreq.service
The module reports the following values: {
"name": "auto-cpufreq.service",
"source": "systemd",
"state": "stopped",
"status": "not-found",
"sub_state": "dead"
}Specifically, since the service is in a "bad" state due to not-found, the module replaces the When testing the module with a # systemctl list-units mcelog.service --no-pager --type service --all --plain
UNIT LOAD ACTIVE SUB DESCRIPTION
mcelog.service loaded failed failed Machine Check Exception Logging Daemon {
"name": "mcelog.service",
"source": "systemd",
"state": "stopped",
"status": "failed",
"sub_state": "failed"
}The state field correctly remains The current version of service_facts may be too simplistic. However, with the new Systemd handles more state/status values than other service sources, and in the future, it might be worth considering a complete rewrite of its dedicated class. However, making drastic changes to long-standing values without proper warnings could lead to significant issues for users. |
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
I made a new change to the integration test tasks. Starting a service that immediately enters the It turns out that the integration test was failing randomly only on To prevent this, I added the To ensure the service doesn’t cause further issues, I added a task in I also re-enable the service immediately after the |
|
I had to modify the I had to add a service cleanup operation after the failed tests in I had to change the In my opinion, the integration tests for |
SUMMARY
The
ansible.builtin.service_factsmodule does not accurately report the state of services when the source is systemd.On hosts using
systemd, the stateexitedordeadindicates that the service is inactive.However, this does not confirm that the service is properly in the stopped state.
According to the code in the
SystemctlScanServiceclass here :the service state on hosts is determined by the
SUBparameter from the following command.Unfortunately, the SUB parameter, which is referenced as
fields[3], is later overridden by thestate_valvariable, which is set tostoppedby default at the beginning.As a result, this leads to the module always returning only two possible outcomes:
stoppedorrunning, rather than accurately reporting the true state of the services.The best solution would be to add a new value,
sub_state, that reflects the exact state fromsystemctl, but only when the source is systemd.I have modified the
service_facts.pyfile by adding the return of a new value,sub_state.statevalue remains unchanged.sub_state, has been added to reflect theSUBstate ofsystemctl.To avoid errors, the
sub_statevalue has been added to both_list_from_unitsand_list_from_unit_files.In
_list_from_unit_files, thesub_statevalue will be identical tostate.I have modified the documentation with sub_state description and example
Fixes #84607
ISSUE TYPE