Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding loop_control.notify_scope #56817

Open
wants to merge 2 commits into
base: devel
from

Conversation

@jtyr
Copy link
Contributor

commented May 22, 2019

SUMMARY

When using notify in a loop, notification targets for all loop items are triggered even if only single loop item has been changed. This PR is adding a loop_control toggle which allows to trigger notification targets only for changed items of the loop.

To the attention of @bcoca.

ISSUE TYPE

Feature Pull Request

COMPONENT NAME

loop_control

ADDITIONAL INFORMATION

See more details and examples in the documentation included in the PR.

@ansibot

This comment has been minimized.

Copy link
Contributor

commented May 22, 2019

@jtyr jtyr force-pushed the jtyr:jtyr-notify_scope branch from 0d81df7 to 48a4dc5 May 23, 2019

@bcoca bcoca added P3 and removed needs_triage labels May 28, 2019

@bcoca
Copy link
Member

left a comment

Also brought up at irc meeting, general consensus is +1 on feature, you might get people bikeshedding on name later though

Show resolved Hide resolved lib/ansible/executor/task_executor.py Outdated

@ansibot ansibot added needs_revision and removed core_review labels May 28, 2019

@jtyr jtyr force-pushed the jtyr:jtyr-notify_scope branch 2 times, most recently from 1634bf4 to 2065f8d May 29, 2019

@jtyr jtyr force-pushed the jtyr:jtyr-notify_scope branch from 2065f8d to 9158710 May 29, 2019

@samdoran samdoran self-assigned this Jun 6, 2019

@@ -497,7 +499,7 @@ def _squash_items(self, items, loop_var, variables):
self._task.args['name'] = name
return items

def _execute(self, variables=None):
def _execute(self, variables=None, notify_scope='task'):

This comment has been minimized.

Copy link
@mkrizek

mkrizek Jun 6, 2019

Contributor

I would turn notify_scope parameter into an instance variable, self._notify_scope. That way you don't have to pass it around.

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

👍 to making this an instance attribute.

self._task.notify is not None and (
notify_scope != 'per_loop_item' or (
notify_scope == 'per_loop_item' and
result['changed']))):

This comment has been minimized.

Copy link
@mkrizek

mkrizek Jun 6, 2019

Contributor

This is probably just me but I had a hard time parsing that. I would change notify_scope != 'per_loop_item' into notify_scope == 'task' and put it all on the one or two lines maybe. Not a blocker, of course.

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

This doesn't account for invalid values. I'm wondering if this would be better as a boolean value rather than a string field. Something like notify_per_item with a default of False.

Are there other values for this option that would make it better suited to a string than a boolean?

If we do keep it as a string value, maybe the options could be task, item or task, per_item. Just throwing out ideas.

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

This is easier to read:

if self._task.notify is not None:
    if notify_per_loop_item:
        if result['changed']:
            result['_ansible_notify'] = self._task.notify
    else:
        result['_ansible_notify'] = self._task.notify

Or using the existing string option:

if self._task.notify is not None:
    if notify_scope not in ['task', 'per_loop_item']:
        raise AnsibleError("Invalid option '{0}' given for notify_scope. Valid options are "
                           "'task' or 'per_loop_item'".format(to_text(notify_scope)))
    elif notify_scope == 'per_loop_item':
        if result['changed']:
            result['_ansible_notify'] = self._task.notify
    else:
        result['_ansible_notify'] = self._task.notify

This comment has been minimized.

Copy link
@mkrizek

mkrizek Jun 7, 2019

Contributor

This doesn't account for invalid values.

Yeah, I realized that when suggested notify_per_item below, too ;-) I was wondering if we had anything like choices for FieldAttribute so we didn't have to check for invalid types here in the code but not that I could find.

This comment has been minimized.

Copy link
@sivel

sivel Jun 7, 2019

Member

The way we have done this before is via something like _validate_debugger. That method effectively does this, but for debugger

This comment has been minimized.

Copy link
@mkrizek

mkrizek Jun 10, 2019

Contributor

Nice. So I'd go with _validate_$whatever_name_we_bikeshed method to check for invalid values. Unless we decide to use a boolean.

@@ -402,6 +402,45 @@ Variable Description
loop_control:
extended: yes

Notification scope in the loop

This comment has been minimized.

Copy link
@mkrizek

mkrizek Jun 6, 2019

Contributor

@acozine @samccann would you mind reviewing the docs part please? Thanks!

@mkrizek

This comment has been minimized.

Copy link
Contributor

commented Jun 6, 2019

Bikeshedding: can we maybe do something like loop_control.notify_per_item which would be bool, no by default as the current behavior?

Unless we plan to add more options in the future.

@@ -497,7 +499,7 @@ def _squash_items(self, items, loop_var, variables):
self._task.args['name'] = name
return items

def _execute(self, variables=None):
def _execute(self, variables=None, notify_scope='task'):

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

👍 to making this an instance attribute.

self._task.notify is not None and (
notify_scope != 'per_loop_item' or (
notify_scope == 'per_loop_item' and
result['changed']))):

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

This doesn't account for invalid values. I'm wondering if this would be better as a boolean value rather than a string field. Something like notify_per_item with a default of False.

Are there other values for this option that would make it better suited to a string than a boolean?

If we do keep it as a string value, maybe the options could be task, item or task, per_item. Just throwing out ideas.

self._task.notify is not None and (
notify_scope != 'per_loop_item' or (
notify_scope == 'per_loop_item' and
result['changed']))):

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

This is easier to read:

if self._task.notify is not None:
    if notify_per_loop_item:
        if result['changed']:
            result['_ansible_notify'] = self._task.notify
    else:
        result['_ansible_notify'] = self._task.notify

Or using the existing string option:

if self._task.notify is not None:
    if notify_scope not in ['task', 'per_loop_item']:
        raise AnsibleError("Invalid option '{0}' given for notify_scope. Valid options are "
                           "'task' or 'per_loop_item'".format(to_text(notify_scope)))
    elif notify_scope == 'per_loop_item':
        if result['changed']:
            result['_ansible_notify'] = self._task.notify
    else:
        result['_ansible_notify'] = self._task.notify

- name: Set handler variables to known value
set_fact:
handler_one: null

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

You could use ~ rather than null.

- name: Test all handlers were run
assert:
that:
- handler_one != None

This comment has been minimized.

Copy link
@samdoran

samdoran Jun 7, 2019

Member

Using a test rather than a comparison is a bit more reliable. Types with Jijna can be a pain.

Suggested change
- handler_one != None
- handler_one is not none
@samccann
Copy link
Contributor

left a comment

one minor doc nit.

------------------------------
.. versionadded:: 2.9

By default, if each loop item triggers different notification target, all targets for all items get triggered even if

This comment has been minimized.

Copy link
@samccann

samccann Jun 20, 2019

Contributor
Suggested change
By default, if each loop item triggers different notification target, all targets for all items get triggered even if
By default, if each loop item triggers a different notification target, all targets for all items get triggered even if
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.