Run a command only on hosts that have low CPU usage

32 views
Skip to first unread message

Eric S

unread,
Jan 29, 2020, 7:48:58 PM1/29/20
to Ansible Project
Hi Folks,
I am looking for a simple way to have Ansible perform the following automation for me:
  1. From a set of N hosts, find out which host has the lowest CPU usage at the moment
  2. Run a command on only that host.
This pattern could be extended to a general case of:

Run a command on a subset of hosts matching a condition which is not static.

This could apply for the following types of use cases:
  • Find out which hosts are running low on disk space, and only expand disk space on the hosts which are running low
  • Find out which hosts are lacking a particular upgrade, and only upgrade those hosts
  • Only run a command on machines which are not currently under heavy load
This seems like a common and desirable enough pattern, but as far as I can tell there is not a well defined way to execute this with Ansible. Is there a simple way to do this with a playbook, or do I need to write a strategy plugin?

Thanks,
Eric

Stefan Hornburg (Racke)

unread,
Jan 30, 2020, 1:28:07 AM1/30/20
to ansible...@googlegroups.com
On 1/30/20 1:48 AM, Eric S wrote:
> Hi Folks,
> I am looking for a simple way to have Ansible perform the following automation for me:
>
> 1. From a set of N hosts, find out which host has the lowest CPU usage at the moment
> 2. Run a command on *only that host*.
>
> This pattern could be extended to a general case of:
>
> Run a command on a subset of hosts matching a condition which is not static.
>
>
> This could apply for the following types of use cases:
>
> * Find out which hosts are running low on disk space, and only expand disk space on the hosts which are running low
> * Find out which hosts are lacking a particular upgrade, and only upgrade those hosts
> * Only run a command on machines which are not currently under heavy load
>
> This seems like a common and desirable enough pattern, but as far as I can tell there is not a well defined way to
> execute this with Ansible. Is there a simple way to do this with a playbook, or do I need to write a strategy plugin?
>
> Thanks,
> Eric

Hello Eric,

you could try to add the hosts to a new group with the "add_host" module and execute the command with delegate_to in
a loop over the hosts in that group.

Regards
Racke

>
> --
> You received this message because you are subscribed to the Google Groups "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> ansible-proje...@googlegroups.com <mailto:ansible-proje...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ansible-project/8425baa9-e324-4f1f-a459-8ca35cca3a54%40googlegroups.com
> <https://groups.google.com/d/msgid/ansible-project/8425baa9-e324-4f1f-a459-8ca35cca3a54%40googlegroups.com?utm_medium=email&utm_source=footer>.


--
Ecommerce and Linux consulting + Perl and web application programming.
Debian and Sympa administration. Provisioning with Ansible.

signature.asc

Eric S

unread,
Jan 30, 2020, 11:24:15 AM1/30/20
to Ansible Project
Racke,
Thanks for your response.

In practice, what would this look like?

So far, I have a playbook that I can use to get a list of CPU values. However, I am having trouble correlating the value of CPU to its corresponding hostname.

---
- hosts: host_list
  gather_facts: false

  tasks:
  - name: Get CPU usage
    shell: "top -b -n 1 | head -n3 | tail -n1 | awk '{print $2}'"
    register: top

  - name: Set CPU fact
    set_fact:
      cpu_list: "{{ ansible_play_hosts | map('extract', hostvars, 'top') | map(attribute='stdout') | list }}"


Is this on the right track, or do I want a different approach entirely?

Thanks,
Eric

On Wednesday, January 29, 2020 at 10:28:07 PM UTC-8, Stefan Hornburg (Racke) wrote:
On 1/30/20 1:48 AM, Eric S wrote:
> Hi Folks,
> I am looking for a simple way to have Ansible perform the following automation for me:
>
>  1. From a set of N hosts, find out which host has the lowest CPU usage at the moment
>  2. Run a command on *only that host*.
>
> This pattern could be extended to a general case of:
>
>     Run a command on a subset of hosts matching a condition which is not static.
>
>
> This could apply for the following types of use cases:
>
>   * Find out which hosts are running low on disk space, and only expand disk space on the hosts which are running low
>   * Find out which hosts are lacking a particular upgrade, and only upgrade those hosts
>   * Only run a command on machines which are not currently under heavy load
>
> This seems like a common and desirable enough pattern, but as far as I can tell there is not a well defined way to
> execute this with Ansible. Is there a simple way to do this with a playbook, or do I need to write a strategy plugin?
>
> Thanks,
> Eric

Hello Eric,

you could try to add the hosts to a new group with the "add_host" module and execute the command with delegate_to in
a loop over the hosts in that group.

Regards
         Racke

>
> --
> You received this message because you are subscribed to the Google Groups "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to

Stefan Hornburg (Racke)

unread,
Jan 30, 2020, 11:43:10 AM1/30/20
to ansible...@googlegroups.com
On 1/30/20 5:24 PM, Eric S wrote:
> Racke,
> Thanks for your response.
>
> In practice, what would this look like?
>
> So far, I have a playbook that I can use to get a list of CPU values. However, I am having trouble correlating the value
> of CPU to its corresponding hostname.
>
> ---
> - hosts: host_list
>   gather_facts: false
>
>   tasks:
>   - name: Get CPU usage
>     shell: "top -b -n 1 | head -n3 | tail -n1 | awk '{print $2}'"
>     register: top
>
>   - name: Set CPU fact
>     set_fact:
>       cpu_list: "{{ ansible_play_hosts | map('extract', hostvars, 'top') | map(attribute='stdout') | list }}"
>
>
> Is this on the right track, or do I want a different approach entirely?
>
> Thanks,
> Eric

Hello Eric,

this can be done, but I doubt that it makes sense to do it with Ansible as above (especially with a lot of hosts).

Collect system metrics on each server with something like Telegraf and base your decisions on that.

Regards
Racke

>
> On Wednesday, January 29, 2020 at 10:28:07 PM UTC-8, Stefan Hornburg (Racke) wrote:
>
> On 1/30/20 1:48 AM, Eric S wrote:
> > Hi Folks,
> > I am looking for a simple way to have Ansible perform the following automation for me:
> >
> >  1. From a set of N hosts, find out which host has the lowest CPU usage at the moment
> >  2. Run a command on *only that host*.
> >
> > This pattern could be extended to a general case of:
> >
> >     Run a command on a subset of hosts matching a condition which is not static.
> >
> >
> > This could apply for the following types of use cases:
> >
> >   * Find out which hosts are running low on disk space, and only expand disk space on the hosts which are running low
> >   * Find out which hosts are lacking a particular upgrade, and only upgrade those hosts
> >   * Only run a command on machines which are not currently under heavy load
> >
> > This seems like a common and desirable enough pattern, but as far as I can tell there is not a well defined way to
> > execute this with Ansible. Is there a simple way to do this with a playbook, or do I need to write a strategy plugin?
> >
> > Thanks,
> > Eric
>
> Hello Eric,
>
> you could try to add the hosts to a new group with the "add_host" module and execute the command with delegate_to in
> a loop over the hosts in that group.
>
> Regards
>          Racke
>
> >
> > --
> > You received this message because you are subscribed to the Google Groups "Ansible Project" group.
> > To unsubscribe from this group and stop receiving emails from it, send an email to
> > ansible...@googlegroups.com <javascript:> <mailto:ansible-proje...@googlegroups.com <javascript:>>.
> <https://groups.google.com/d/msgid/ansible-project/8425baa9-e324-4f1f-a459-8ca35cca3a54%40googlegroups.com?utm_medium=email&utm_source=footer
> <https://groups.google.com/d/msgid/ansible-project/8425baa9-e324-4f1f-a459-8ca35cca3a54%40googlegroups.com?utm_medium=email&utm_source=footer>>.
>
>
>
> --
> Ecommerce and Linux consulting + Perl and web application programming.
> Debian and Sympa administration. Provisioning with Ansible.
>
> --
> You received this message because you are subscribed to the Google Groups "Ansible Project" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
> ansible-proje...@googlegroups.com <mailto:ansible-proje...@googlegroups.com>.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/ansible-project/851f1bd7-dfa4-4c9b-b1c5-ae278766ff72%40googlegroups.com
> <https://groups.google.com/d/msgid/ansible-project/851f1bd7-dfa4-4c9b-b1c5-ae278766ff72%40googlegroups.com?utm_medium=email&utm_source=footer>.
signature.asc

Vladimir Botka

unread,
Jan 30, 2020, 1:08:19 PM1/30/20
to Eric S, ansible...@googlegroups.com
On Thu, 30 Jan 2020 08:24:14 -0800 (PST)
Eric S <ems...@gmail.com> wrote:

> So far, I have a playbook that I can use to get a list of CPU values.
> However, I am having trouble correlating the value of CPU to its
> corresponding hostname.
>
> ---
> - hosts: host_list
> gather_facts: false
>
> tasks:
> - name: Get CPU usage
> shell: "top -b -n 1 | head -n3 | tail -n1 | awk '{print $2}'"
> register: top
>
> - name: Set CPU fact
> set_fact:
> cpu_list: "{{ ansible_play_hosts | map('extract', hostvars, 'top') |
> map(attribute='stdout') | list }}"

Create list of dictionaries

- name: Set CPU fact
set_fact:
cpu_list: "{{ ansible_play_hosts|
map('extract', hostvars)|
list|
json_query('[].{host: inventory_hostname,
cpu: top.stdout}') }}"
run_once: true

Find the minimal load

- set_fact:
cpu_min: "{{ cpu_list|json_query('[].cpu')|min }}"
run_once: true

and find the host with this minimal load

- set_fact:
host_min: "{{ cpu_list|json_query(query)|first }}"
vars:
query: "[?cpu == '{{ cpu_min }}'].host"
run_once: true

HTH,

-vlado
Reply all
Reply to author
Forward
0 new messages