Iterating over a list of targetted minions

502 views
Skip to first unread message

Matt

unread,
Feb 3, 2016, 2:43:39 PM2/3/16
to Salt-users
Is there a way to loop over a list of minion ids that I'm targeting? Not sure if I'm asking an obvious question but there a over-simplistic example of what I'm trying to accomplish:


{% set targeted_minions = <<< list of minion ids returned by salt -C "G@tier:production and G@location:uk" >>> %}

{% for minion in targeted_minions %}
{{ minion }}:
  cmd.run:
    - name: echo {{ minion }}

{% endfor %}


I'd like to avoid writing a python module if possible.

Thanks,
Matt

Colton Myers

unread,
Feb 3, 2016, 3:37:58 PM2/3/16
to salt-...@googlegroups.com
If this is in a normal state, the answer is "probably not". This is because states are evaluated on the minion, and the minion doesn't know enough about other minions to be able to compile that list.

You might be able to compile your own list by having a minion run a peer publishing command, with `publish.publish`. More info about publishing here: https://docs.saltstack.com/en/latest/ref/peer.html

However, this is pretty hacky as it adds a good chunk of overhead to the state compilation, with minions querying other minions all the time. The Salt Mine might be a good workaround for this, less overhead. Just have to have all minions sending a test.ping up to the mine or something, so you can query those results for a list of minions. https://docs.saltstack.com/en/latest/topics/mine/

Hopefully that gives you a couple of decent starting points.

--
Colton Myers
Core Engineer, SaltStack
@basepi on Twitter/Github/IRC

Registration for SaltConf 2016 is open! http://saltconf.com/register/

--
You received this message because you are subscribed to the Google Groups "Salt-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to salt-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matt

unread,
Feb 3, 2016, 4:29:04 PM2/3/16
to Salt-users
Colton,
I've missed a crucial piece of information, it's actually not a normal state but an orchestration state that I'm trying to do this in in order to do a rolling deployment scenario.

Seth House

unread,
Feb 4, 2016, 2:10:51 AM2/4/16
to salt users list
For Orchestrate I'd recommend grabbing the list of minions from the
cached grains on the master prior to sending executions out to
minions. Something like this:

{% set batchA = salt.saltutil.runner(
'cache.grains',
tgt='G@tier:production and G@location:uk',
expr_form='compound').keys() %}

{% set batchB = salt.saltutil.runner(
'cache.grains',
tgt='G@tier:production and G@location:eu',
expr_form='compound').keys() %}

{% set batchC = salt.saltutil.runner(
'cache.grains',
tgt='G@tier:production and G@location:us',
expr_form='compound').keys() %}

{# Run simultaneously on all minions in batchA. #}
first_batch:
salt.function:
- tgt: {{ batchA | json() }}
- expr_form: list
- name: cmd.run
- kwarg:
cmd: hostname

{# Wait for batchA to finish successfully before
moving on to batchB. #}
second_batch:
salt.function:
- tgt: {{ batchB | json() }}
- expr_form: list
- name: cmd.run
- kwarg:
cmd: hostname
- require:
- salt: first_batch

{# Execute one-at-a-time for minions in batchC. #}
{% for minion_id in batchC %}
final_batch_{{ minion_id }}:
salt.function:
- tgt: {{ minion_id }}
- name: cmd.run
- kwarg:
cmd: hostname
- require:
- salt: second_batch
{% endfor %}

Matt

unread,
Feb 5, 2016, 4:40:00 PM2/5/16
to Salt-users, se...@eseth.com
Seth, that sounds promising. I'll give it a shot.

Thanks!
Matt

Matt

unread,
Mar 10, 2016, 11:24:29 PM3/10/16
to Salt-users
The above examples were just what I was looking for, I've taken the pieces that I was most interested in to use for my testing an put them in the state below.

rolling_deployment.sls:

{% set minions = salt.saltutil.runner('cache.mine', tgt='G@location:uk', expr_form='compound') %}

{% for minion_id in minions %}
deploy_{{ minion_id }}:


salt.function:
- tgt: {{ minion_id }}
- name: cmd.run
- kwarg:

cmd: echo "Deploying {{ minion_id }}"
{% endfor %}


I changed 'cache.grains' to 'cache.mine' so that it doesn't print out all grains for all minions, but I'm not sure if it will cause any issues.

Are there any scenarios where using the cache runner altogether can be unreliable?

Below is the output of running the orchestration state:

salt-run state.orchestrate orch.rolling_deployment

Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.AttributeError'> ignored
hostname2.localdomain.net:
----------
hostname1.localdomain.net:
----------
saltmaster1.localdomain.net_master:
----------
ID: deploy_hostname1.localdomain.net
Function: salt.function
Name: cmd.run
Result: True
Comment: Function ran successfully. Function cmd.run ran on hostname1.localdomain.net.
Started: 22:06:38.756495
Duration: 255.561 ms
Changes:
hostname1.localdomain.net:
Deploying hostname1.localdomain.net
----------
ID: deploy_hostname2.localdomain.net
Function: salt.function
Name: cmd.run
Result: True
Comment: Function ran successfully. Function cmd.run ran on hostname2.localdomain.net.
Started: 22:06:39.012409
Duration: 254.963 ms
Changes:
hostname2.localdomain.net:
Deploying hostname2.localdomain.net

Summary
------------
Succeeded: 2 (changed=2)
Failed: 0
------------
Total states run: 2


Is the python recursion error something I should be worried about? I'm running salt off of a RedHat 6 / python2.6 environment.

Thanks!

Seth House

unread,
Mar 11, 2016, 9:34:23 AM3/11/16
to salt users list
On Thu, Mar 10, 2016 at 9:24 PM, Matt <matt...@gmail.com> wrote:
> I changed 'cache.grains' to 'cache.mine' so that it doesn't print out all grains for all minions, but I'm not sure if it will cause any issues.

If your Mine configuration has all your minions reporting in then the
end-result is functionally the same. Just keep this usage in mind if
you ever change your Mine configuration to run on a subset of minions.
I am unsure if the Mine cache is cleaned up when minion keys are
deleted.

It sounds like the cache runner needs to be updated to not print
values out to the CLI when invoked.

> Are there any scenarios where using the cache runner altogether can be unreliable?

It stays pretty up-to-date. It's updated each time the minion connects
to the master and when grains are refreshed.

> Below is the output of running the orchestration state:
> Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' in <type 'exceptions.AttributeError'> ignored

I'm not sure which operation could be returning this error, offhand.
Probably worth investing though.

Matt

unread,
Apr 1, 2016, 11:03:40 AM4/1/16
to Salt-users
What I ended up doing is writing a simple runner below:

_modules/runners/minions.py:

import salt.client

def list(tgt=None, expr_form='compound'):

    client = salt.client.LocalClient(__opts__['conf_file'])
    minions = client.cmd(tgt, 'test.ping', expr_form='compound', timeout=5)

    return minions

In my orchestration file I have:
{% set minions = salt.saltutil.runner('minions.list',
                                      tgt='G@role:some_role',

                                      expr_form='compound') %}

{% for minion_id in minions %}

deploy_{{ minion_id }}:
  salt.function:
    - tgt: {{ minion_id }}
    - name: cmd.run
    - kwarg:
        cmd: echo "Deploying {{ minion_id }}"

{% endfor %}

With that said, I am still seeing the maximum recursion depth exceeded warning so It looks like this is a broader issue with the runners perhaps.

Reply all
Reply to author
Forward
0 new messages