-
Notifications
You must be signed in to change notification settings - Fork 21
refactor: Ansible 2.19 support #191
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
Conversation
Reviewer's GuideRefactor SSH role tasks and templates to support Ansible 2.19’s stricter immutability and boolean evaluation by replacing multi-line Jinja conditionals with inline filters and ternary expressions, adding explicit "is not none" checks, and eliminating mutable constructs. Class diagram for updated SSH role variable resolutionclassDiagram
class SSHRoleVars {
+ssh_skip_defaults
+ssh_user
+ssh_drop_in_name
+__ssh_supports_drop_in
+ssh_config_file
+ansible_facts
+ssh_config_owner
+ssh_config_group
+ssh_config_mode
+__ssh_skip_defaults
+__ssh_config_file
+__ssh_config_owner
+__ssh_config_group
+__ssh_config_mode
}
SSHRoleVars : __ssh_skip_defaults = ssh_skip_defaults if ssh_skip_defaults != 'auto' else (ssh_user is not none) or (ssh_drop_in_name is not none and __ssh_supports_drop_in)
SSHRoleVars : __ssh_config_file = ssh_config_file if ssh_config_file is not none else ansible_facts['getent_passwd'][ssh_user][4] + '/.ssh/config' if ssh_user is not none and ansible_facts['getent_passwd'] is defined else __ssh_drop_in_template | replace('{name}', ssh_drop_in_name) if ssh_drop_in_name is not none and __ssh_supports_drop_in else '/etc/ssh/ssh_config'
SSHRoleVars : __ssh_config_owner = ssh_config_owner if ssh_config_owner is not none else ssh_user if ssh_user is not none else 'root'
SSHRoleVars : __ssh_config_group = ssh_config_group if ssh_config_group is not none else ssh_user if ssh_user is not none and ansible_facts['getent_passwd'] is defined else 'root'
SSHRoleVars : __ssh_config_mode = ssh_config_mode if ssh_config_mode is not none else '0600' if ssh_user is not none else '0644'
Class diagram for updated ssh_config.j2 macrosclassDiagram
class ssh_config_j2 {
+macro render_option(key, value, indent=false)
+macro body_option(key, override)
}
ssh_config_j2 : render_option checks value is defined and not none
ssh_config_j2 : render_option handles true, false, list, and string values
ssh_config_j2 : body_option checks override, ssh[key], __ssh_defaults[key] for not none
ssh_config_j2 : body_option calls render_option directly
ssh_config_j2 --> ssh_config_j2 : render_option used by body_option
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@martinpitt this supersedes #190 The key was realizing that the the macro must return a value - the implicit return value is |
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.
Hey @richm - I've reviewed your changes - here's some feedback:
- The inline nested ternary chains for __ssh_skip_defaults, __ssh_config_file, etc., are becoming hard to parse—consider breaking them into separate set_fact tasks or using multi-line Jinja if/elif blocks for better readability.
- In the render_option macro, you now guard against value is none, but you might also want to explicitly handle empty strings or zero values so they don’t get inadvertently skipped.
- You’ve quoted the file mode strings as '0600' and '0644'—please verify that Ansible interprets these as octal permissions and not as plain string literals.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The inline nested ternary chains for __ssh_skip_defaults, __ssh_config_file, etc., are becoming hard to parse—consider breaking them into separate set_fact tasks or using multi-line Jinja if/elif blocks for better readability.
- In the render_option macro, you now guard against value is none, but you might also want to explicitly handle empty strings or zero values so they don’t get inadvertently skipped.
- You’ve quoted the file mode strings as '0600' and '0644'—please verify that Ansible interprets these as octal permissions and not as plain string literals.
## Individual Comments
### Comment 1
<location> `tasks/main.yml:79` </location>
<code_context>
+ __ssh_config_group: "{{ ssh_config_group if ssh_config_group is not none
+ else ssh_user if ssh_user is not none and ansible_facts['getent_passwd'] is defined
+ else 'root' }}"
+ __ssh_config_mode: "{{ ssh_config_mode if ssh_config_mode is not none
+ else '0600' if ssh_user is not none
+ else '0644' }}"
</code_context>
<issue_to_address>
The default mode values are now quoted as strings, which may differ from previous behavior.
Previously, mode values were integers (e.g., 600/644); now they are strings ('0600'/'0644'). Ensure downstream code handles the type change to avoid permission issues.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| __ssh_config_mode: "{{ ssh_config_mode if ssh_config_mode is not none | ||
| else '0600' if ssh_user is not none |
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.
issue (bug_risk): The default mode values are now quoted as strings, which may differ from previous behavior.
Previously, mode values were integers (e.g., 600/644); now they are strings ('0600'/'0644'). Ensure downstream code handles the type change to avoid permission issues.
|
[citest] |
martinpitt
left a 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.
Thanks @richm for figuring this uot! The "return empty string" escaped me in my attempts, nor did the various LLMs know about it. Now the template change looks very sensible.
BTW, the {{- '' -}} emoji reminds me of a toad or a lobster looking at you!
I'm not the primary reviewer, just some comment from the peanut gallery.
Ansible 2.19 introduces some big changes https://docs.ansible.com/ansible/devel/porting_guides/porting_guide_core_2.19.html One big change is that data structures are no longer mutable by the use of python methods such as `__setitem__`, `setdefault`, `update`, etc. in Jinja constructs. Instead, items must use filters or other Jinja operations. One common idiom is to mutate each element in a list. Since we cannot do this "in-place" anymore, a common way to do this is: ```yaml - name: Construct a new list from an existing list and mutate each element set_fact: __new_list: "{{ __new_list | d([]) + [mutated_item] }}" loop: "{{ old_list }}" mutated_item: "{{ some value based on item from old list }}" - name: Reset original old list set_fact: old_list: "{{ __new_list }}" ``` Similarly with `dict` items: ```yaml - name: Construct a new dict from an existing dict and mutate each element set_fact: __new_dict: "{{ __new_dict | d({}) | combine(mutated_item) }}" loop: "{{ old_dict | dict2items }}" mutated_item: "{{ {item.key: mutation of item.value} }}" - name: Reset original old dict set_fact: old_dict: "{{ __new_dict }}" ``` Another big change is that a boolean expression in a `when` or similar construct must be converted to a boolean - we cannot rely on the implicit evaluation in a boolean context. For example, if `var` is some iterable, like a `dict`, `list`, or `string`, you used to be able to evaluate an empty value in a boolean context: ```yaml when: var # do this only if var is not empty ``` You now have to explicitly test for empty using `length`: ```yaml when: var | length > 0 # do this only if var is not empty ``` Similarly for `int` values - you cannot rely on `0` being evaluated as false and non-zero true - you must explicitly compare the values with `==` or `!=` These are the biggest changes. See the porting guide for others. Signed-off-by: Rich Megginson <rmeggins@redhat.com>
martinpitt
left a 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.
LGTM now, cheers! However, leaving final review to @Jakuje
|
And we will likely need similar changes in the server role in https://github.com/willshersystems/ansible-sshd |
Yes - there have already been ansible 2.19 issues reported there |
|
[citest] |
1 similar comment
|
[citest] |
|
[citest] |
Ansible 2.19 introduces some big changes
https://docs.ansible.com/ansible/devel/porting_guides/porting_guide_core_2.19.html
One big change is that data structures are no longer mutable by the use of python
methods such as
__setitem__,setdefault,update, etc. in Jinja constructs.Instead, items must use filters or other Jinja operations.
One common idiom is to mutate each element in a list. Since we cannot do this
"in-place" anymore, a common way to do this is:
Similarly with
dictitems:Another big change is that a boolean expression in a
whenor similar constructmust be converted to a boolean - we cannot rely on the implicit evaluation in
a boolean context. For example, if
varis some iterable, like adict,list,or
string, you used to be able to evaluate an empty value in a boolean context:You now have to explicitly test for empty using
length:Similarly for
intvalues - you cannot rely on0being evaluated as falseand non-zero true - you must explicitly compare the values with
==or!=These are the biggest changes. See the porting guide for others.
Signed-off-by: Rich Megginson rmeggins@redhat.com
Summary by Sourcery
Refactor SSH role templates and task definitions to comply with Ansible 2.19’s porting requirements by removing mutable operations, enforcing explicit boolean evaluations, and converting multi-line conditionals into inline expressions.
Enhancements: