Here is the Ansible code for selecting services that have been running for more than a certain time:
---
- name: Find running services
hosts: remote_host
gather_facts: no
vars:
hours_threshold: 15
tasks:
- name: Get list of running services
command: systemctl list-units --type=service --state=running
register: running_services
- name: Filter services
set_fact:
s_services: >-
{{
running_services.stdout_lines
| select('search', 'nginx’)
| list
}}
- name: result
debug:
msg: "{{ s_services }}"
- name: Get details of services
command: systemctl show {{ item }} --property=ActiveEnterTimestamp
register: s_service_details
loop: "{{ s_services }}"
when: s_services | length > 0
- name: Debug output of Redis services with start time
debug:
msg: "s service: {{ item.item }} started at {{ item.stdout }}"
loop: "{{ s_service_details.results }}"
when: s_service_details.results | length > 0
- name: s_service_details.results
debug:
msg: "{{ s_service_details.results }}"
- name: Set the threshold time for filtering
command: date -d "{{ hours_threshold }} hours ago" +%s
register: threshold_time
- name: threshold_time
debug:
msg: "{{ threshold_time }}"
- name: Extract and convert ActiveEnterTimestamp to epoch
set_fact:
redis_service_details_epoch: >-
{{
redis_service_details.results
| map(attribute='stdout')
| map('regex_findall', 'ActiveEnterTimestamp=(.*)')
| map('first')
| select('match', '.+')
| map('trim')
| zip(redis_services | map('regex_replace', '.[^.]*$', ''))
| map('join', ' : ')
| map('first')
| map('to_datetime', '%a %Y-%m-%d %H:%M:%S %Z')
| map('timestamp')
| list
}}
- name: s_service_details_epoch
debug:
msg: "{{ redis_service_details_epoch }}"
The task "Set the threshold time for filtering" gets a timestamp in epoch format from the set value. With this label, you need to compare the start time of each service and the services that work more than the set value, output them to the final list in order to run the list data in a loop and call the desired playbook. to pass the names of each found service in turn as a variable ‘service_name’.
however, in a loop, it is not possible to perform such a conversion. I’m getting errors.
at the output of this block of code
| map(attribute='stdout')
| map('regex_findall', 'ActiveEnterTimestamp=(.*)')
| map('first')
| select('match', '.+')
| map('trim')
| zip(redis_services | map('regex_replace', '.[^.]*$', ''))
| map('join', ' : ')
I get a value like :
"Fri 2024-10-18 22:26:53 CEST : nginx-reactive"
Then it needs to be converted to the format:
"1729181112 : nginx-reactive"
Then you need to compare all the epoch values of each found service with the value in the variable : threshold_time
Then, you need to save the resulting list into a separate variable that you can work with further.
This is how you can perform the conversion of a single service:
---
- name: Find running Redis services
hosts: localhost
gather_facts: no
vars:
expire_date: Thu 2024-09-17 11:05:12 CEST
tasks:
- name: Convert expire_date to epoch
set_fact:
expire_date_epoch: "{{ (expire_date | to_datetime('%a %Y-%m-%d %H:%M:%S %Z')).timestamp() | int }}"
- name: Display epoch time
debug:
msg: "Epoch time: {{ expire_date_epoch }}"
, but that’s all I know so far
Does anyone have any ideas on how to perform the conversion?
2
Answers
After you get the running services
Use the filter community.general.jc to parse the stdout. You must install jc on the controller.
gives
In your example, you’re looking for the nginx service. I’m running this example in my notebook without nginx installed. Let’s test ssh instead
gives
Then you iterate this list and get the property ActiveEnterTimestamp
When you iterate the results
gives (abridged)
Declare the lists of units, stdout, and create the dictionary s_dict
gives
Iterate the dictionary and convert the date to epoch
gives
Further processing should be trivial. For example, selecting systemd
gives (abridged)
Example of a complete playbook for testing
Your assumption that you need to convert to an epoch in order to do date comparison is incorrect. As soon as you have the dates of your list and the threshold date as a Python
datetime
object, you can do comparisons between them.For example, if you want to list all items of a list that are prior to a threshold date you can use the
reject
filter on your list.Given:
Which yields:
And so, if you have a list of services in one list and a list of dates in the other, you can list the services running prior to the threshold
Gives: