-
Notifications
You must be signed in to change notification settings - Fork 128
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
Fix #89 by ignoring only keys which are actually used in Pillar 'postfix:mapping' #90
Conversation
'sender_canonical_maps', | ||
] %} | ||
{%- endif -%} | ||
{%- set processed_parameters = salt['pillar.get']('postfix:mapping', {}).keys() | list %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alxwr I don't think you need additional list
filter. The keys()
method will always return a new list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Python 3.6 keys()
returns a dict_keys
object, so the list
is mandatory.
Without | list
:
jinja2.exceptions.UndefinedError: 'dict_keys object' has no attribute 'append'
As far as I understand it: In Python 3.6 keys()
of an OrderedDict
object returns a view (which may change) on the keys of the object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, thanks for pointing me out to Python 3.6 specifics, I wasn't aware of that.
However, still think it looks weird. As I can tell from the code, the processed_parameters
used only once to verify the key exists. No need for such complexity.
We could avoid making the list at all:
{%- set processed_parameters = salt['pillar.get']('postfix:mapping', {}) %}
Then update the key instead of appending at line 14:
{%- do processed_parameters.update({parameter: value}) %}
Finally, at line 130 the if
statement will work the same way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vutny Thanks for your suggestions regarding the elegance of the code. I appreciate that.
processed_parameters
was a list, therefore I kept it that way. In my mind it makes more sense to manage a list of parameter names than to needlessly copy their values. postfix:mapping
's contents may be quite large. Therefore I suggest we stick with the list.
I disagree with using a dict instead of a list, but if this is non-negotiable, I'll give way. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alxwr No worries, I would just like to make things here as portable as possible because of two reasons:
- Generally using Python methods directly is undesirable, unless there's no other clear way.
As we've already learned, different Python version have "smaaaall" differences. And the Jinja code is not really Python, it is a layer on top. So it is better to go with Jinja semantics as much as possible in common situations. - The most heavy call here is
pillar.get
. It needs to fork minion process, talk to the master via message bus and network layer, receive probably megabytes back, cache it, deserialize and finally return back to the caller.
Lots of stuff is going on under the hood. Comparing to that, storing even a big dict in temporary memory is nothing.
If your concern is that holding the values is unnecessary, we could use pillar.keys function! Nothing else need to be changed then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vutny Then we're on the same page. :-) Thanks for the thorough explanation!
Why didn't I think of pillar.keys
in the first place? O.o
Thanks for the review and the suggestion! I updated the PR.
The | list
is needed because of Py3.6: "jinja2.exceptions.UndefinedError: 'dict_keys object' has no attribute 'append'".
@@ -21,6 +21,7 @@ | |||
{%- else %} | |||
{#- Some settings need order, handle OrderedDict #} | |||
{% for item in data %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can simply unpack data in the for
loop right away:
{% for k, v in data %}
{{ format_value(k, v) }}
{%- endfor -%}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can simply unpack data in the
for
loop right away:
Just tried that. It won't fly in Python 3.6:
ValueError: not enough values to unpack (expected 2, got 1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I have mixed the list of dicts with the list of tuples. Your changes definitely looks great.
postfix/files/main.cf
Outdated
'sender_canonical_maps', | ||
] %} | ||
{%- endif -%} | ||
{%- set processed_parameters = salt['pillar.keys']('postfix:mapping') | list %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alxwr Would you mind to add a comment stating why we need list
filter here?
We know, because of Python 3.6, but others would appreciate that greatly. 😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alxwr Would you mind to add a comment stating why we need
list
filter here?
We know, because of Python 3.6, but others would appreciate that greatly. smiley
Added comment. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you also need to prepend the |default([], true)
filter before the list
, since if the Pillar does not exist, the renderer returns KeyError: u'Pillar key not found: postfix:mapping'
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vutny good catch! :-) Updated the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vutny We still get that error even with |default([], true)
:
KeyError: 'Pillar key not found: postfix:mapping'
I'd switch back to
{%- set processed_parameters = salt['pillar.get']('postfix:mapping', {}).keys() | list %}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like having pillar.keys
here is not an option here. The exception is raised on the Salt module level, so the default
filter is no use. I guess we need to revert back to the get
method and either continue with dict to avoid dict_keys object
error, or convert it to a list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd stick with the list. After all its usable in Py2.7 and Py3.x without jumping through loops.
599f688
to
cdc4c5e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for trying my suggestions, @alxwr 😄
@vutny Thanks for making me re-think my code and learn new details. :-) |
With this change the following becomes feasible:
resulting in
This allows also for multiple maps within
virtual_alias_maps
as mentioned in #89 and #83 (comment) by @roskens.I also fixed
mapping.j2
along the way. It didn't work with Python 3.6.Tested on FreeBSD 11.2.