How to kill a running process using ansible?
Asked Answered
T

5

25

I have an ansible playbook to kill running processes and works great most of the time!, however, from time to time we find processes that just can't be killed so, "wait_for" gets to the timeout, throws an error and it stops the process.

The current workaround is to manually go into the box, use "kill -9" and run the ansible playbook again so I was wondering if there is any way to handle this scenario from ansible itself?, I mean, I don't want to use kill -9 from the beginning but I maybe a way to handle the timeout?, even to use kill -9 only if process hasn't been killed in 300 seconds? but what would be the best way to do it?

These are the tasks I currently have:

- name: Get running processes
  shell: "ps -ef | grep -v grep | grep -w {{ PROCESS }} | awk '{print $2}'"
  register: running_processes

- name: Kill running processes
  shell: "kill {{ item }}"
  with_items: "{{ running_processes.stdout_lines }}"

- name: Waiting until all running processes are killed
  wait_for:
    path: "/proc/{{ item }}/status"
    state: absent
  with_items: "{{ running_processes.stdout_lines }}"

Thanks!

Tinworks answered 1/10, 2017 at 18:48 Comment(1)
Use shell only when shell functionality is required. command: "kill {{ item }}"Rupe
K
65

You could ignore errors on wait_for and register the result to force kill failed items:

- name: Get running processes
  shell: "ps -ef | grep -v grep | grep -w {{ PROCESS }} | awk '{print $2}'"
  register: running_processes

- name: Kill running processes
  shell: "kill {{ item }}"
  with_items: "{{ running_processes.stdout_lines }}"

- wait_for:
    path: "/proc/{{ item }}/status"
    state: absent
  with_items: "{{ running_processes.stdout_lines }}"
  ignore_errors: yes
  register: killed_processes

- name: Force kill stuck processes
  shell: "kill -9 {{ item }}"
  with_items: "{{ killed_processes.results | select('failed') | map(attribute='item') | list }}"
Kiva answered 3/10, 2017 at 9:9 Comment(4)
Can I use this in a bog post? (with link back to this reply) @EricTraditional
Btw, this will wait for {{timeout}} seconds per process, so 5 processes will result in 5*{{timeout}}. I wonder if this can be improved via async..Traditional
Can you please explain "{{ killed_processes.results | select('failed') | map(attribute='item') | list }}" ? I am new to Ansible and I am looking for a set of tasks that would kill a set of processes reliably.Kerk
Instead of using the long ps command ps -ef | grep -v grep | grep -w {{ PROCESS }} | awk '{print $2}' you can do it all with ps ps -C {{ PROCESS }} -o pid= This will only print the pid of the command PROCESS. the "-C {{ PROCESS }}" is equivalent to the first 3 commands in the pipe. the "-o pid=" prints only the PID numbers without the header. An even easier solution is "pgrep {{ PROCESS }}", which does the same thing. $0.02Backwash
D
6

Use pkill(1) instead of grep+kill.

Definitive answered 7/4, 2020 at 5:42 Comment(0)
S
4

The killall command has a wait option that might be useful.

Install psmisc:

tasks:
  - apt: pkg=psmisc state=present

Then use killall like this:

tasks:
  - shell: "killall screen --wait"
    ignore_errors: true # In case there is no process

-w, --wait: Wait for all killed processes to die. killall checks once per second if any of the killed processes still exist and only returns if none are left.

Spanos answered 3/8, 2020 at 9:17 Comment(1)
So elegant compared to the other answers!Madlin
D
4

After some investigations and struggling with ansible_linter, below an alternative way (eg. without use of ignore_error)

- name: "disable and stop PROCESS"
  service:
    name: PROCESS
    enabled: no
    state: stopped
  tags:
    - stop

- name: "evaluate running PROCESS processes from remote host"
  command: "/usr/bin/pgrep PROCESS"
  register: running_PROCESS
  failed_when: running_PROCESS.rc > 1
  changed_when: 
    - running_PROCESS.rc == 0
  tags:
    - stop

- name: "pkill PROCESS running processes"
  command: "/usr/bin/pkill PROCESS"
  register: kill_PROCESS
  changed_when: kill_PROCESS.rc == 0
  when: running_PROCESS.stdout_lines | length > 0
  tags:
    - stop

- name: "check PROCESS processes"
  wait_for:
    path: "/proc/{{ item }}/status"
    state: absent
  with_items: "{{ running_PROCESS.stdout_lines }}"
  when: running_PROCESS.stdout_lines | length > 0
  tags:
    - stop

- name: "force kill stuck PROCESS processes"
  command: "/usr/bin/pkill -9 PROCESS"
  register: kill9_PROCESS
  changed_when: kill9_PROCESS.rc == 0
  failed_when: kill9_PROCESS.rc > 1
  when:
    - running_PROCESS.stdout_lines | length > 0
  tags:
    - stop
Debutant answered 1/9, 2021 at 16:35 Comment(0)
J
0

This Code Worked for me

- hosts: ubuntu
  become: yes
  tasks:
  - name: Get Apache PIDs
    shell:
      cmd: ps -ef | grep -v grep | grep -w apache2 | awk '{print $2}' | awk 'FNR == 1 {print}'
      warn: false
    changed_when: false
    check_mode: false
    register: apache_pids

  - name: Kill running processes
    shell: "kill {{ item }}"
    with_items:
    - "{{ apache_pids.stdout_lines }}"

  - name: Show PIDs
    debug:
      var: apache_pids
Joviality answered 15/3, 2023 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.