Conversation
|
Hi @flynn1973, thank you for submitting this pull-request! |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
dagwieers
left a comment
There was a problem hiding this comment.
LGTM, some cosmetic changes and an important fix to documentation.
| options=dict(type='list', required=True), | ||
| state=dict(type='str', default='present', choices=['absent', 'present']) | ||
| ), | ||
| supports_check_mode=False, |
There was a problem hiding this comment.
It would be nice if this module supported check-mode.
|
A few ideas to improve this module:
|
This comment has been minimized.
This comment has been minimized.
|
@flynn1973 There is still a long list of issues to resolve before we can even start considering this module. |
Co-Authored-By: flynn1973 <[email protected]>
Co-Authored-By: flynn1973 <[email protected]>
Co-Authored-By: flynn1973 <[email protected]>
Co-Authored-By: flynn1973 <[email protected]>
Co-Authored-By: flynn1973 <[email protected]>
Co-Authored-By: flynn1973 <[email protected]>
Co-Authored-By: flynn1973 <[email protected]>
aec9cde to
cb0e68c
Compare
|
@flynn1973 I fixed all the open issues from CI. But we need to work on:
|
cb0e68c to
907ddc5
Compare
|
@dagwieers ad integration tests: i use this module on a daily basis and it works smoothly. |
@flynn1973 there is also a command lssec. It lists attributes in the security stanza files. |
| path: /etc/security/user | ||
| stanza: ldapuser | ||
| options: | ||
| - SYSTEM=LDAP |
There was a problem hiding this comment.
To me it seems more logical if the format is not a list, but a dictionary.
options:
SYSTEM: LDAP
registry: LDAP
logintimes: :0800-1700The only reasons for using a list here, would be to ensure a specific order for processing, or to ensure that a specific key can be duplicate (so provided keys are not unique). But I don't think these are no applicable here.
There was a problem hiding this comment.
If you are worried about breaking backward compatibility with existing users, you can use type: raw and test if a string, a list or a dict was provided, and handle strings as key=val, use dicts as an iterable key: value store, and a list could contain either of those two.
And then only document/showcase the dicts syntax, and provide a deprecation message for people using a list or a string. Which could then be removed after 4 major releases (which is what we typically do).
| module.fail_json(msg='Failed to run chsec command (present).', rc=rc, stdout=stdout, stderr=stderr) | ||
| else: | ||
| msg = 'stanza added' | ||
| changed = True |
There was a problem hiding this comment.
There is no guarantee something was changed here. So this would mean the module can only either fail or report changes.
| yield element | ||
|
|
||
| command = [chsec_command, '-f', filename, '-s', '%s' % stanza] | ||
| options = list(arguments_generator(options)) |
There was a problem hiding this comment.
It's probably better to loop over the items and check the value before changing, so you can report back if there was a change or not.
|
I've written a proposal below for what I think the behaviour of the aix_chsec module should have, with a few open design questions. I'd like aix_chsec to be in 2.9, so am looking for responses! SUMMARYBelow is a IBM AIX chsec module design proposal. I've been trying to write a role to 'easily' wrap up the IBM AIX chsec command and make it idempotent. While I've got it (mostly) working here, I'd rather help to make a module to perform this work instead of maintaining such a clunky role. COMPONENT NAMEaix_chsec IdempotencyWe can make the tool idempotent by first checking the output of I'm achieving this in the ansible-role-aix-chsec using something similar to: shell: >
( lssec -f '{{ file }}' -s '{{ stanza }}' -a '{{ key }}' | grep -q '{{ stanza }} {{ key }}={{ value }}' ) && echo nochange || chsec -f '{{ file }}' -s '{{ stanza }}' -a '{{ key }}={{ value }}'ScopeThis module could be part of a larger module to manage many types of AIX settings (aix_settings ?), or simply focus on the chsec command itself. For now we can focus on aix_chsec. Potential Layout(s)'Simple'One example implementation with multiple key/value being set within a single files+stanza at a time: - name: Name of Task
aix_chsec:
file: filename
stanza: stanzaname
attributes:
key1: value1
key2: value2
keyN: valueN
state: [ present, absent ]
backup: bool (default no, timestamped backup before making changes.)This would return
Real world use:
---
- hosts: targetserver
gather_facts: no
vars:
example_chsec:
- file: /etc/security/user
stanza: default
attrs:
logintimes: ":0800-1700"
- file: /etc/security/limits
stanza: joe
attrs: [ cpu: 3600 ]
- file: /etc/security/limits
stanza: charlie
attrs:
cpu: 3600
remote_user: deploy
- tasks:
name: Example chsec
aix_chsec:
file: "{{ item.file }}"
stanza: "{{ item.stanza }}"
attrs: "{{ item.attrs }}"
loop:
- "{{ example_chsec }}"The example_chsec YAML above converts to the following JSON: {
"example_chsec": [
{
"file": "/etc/security/user",
"stanza": "default",
"attrs": {
"logintimes": ":0800-1700"
}
},
{
"file": "/etc/security/limits",
"stanza": "joe",
"attrs": {
"cpu": 3600
}
},
{
"file": "/etc/security/limits",
"stanza": "charlie",
"attrs": {
"cpu": 3600,
"file": -1
}
}
]
}'Nested' StanzasWe could 'nest' stanzas for a single file within a single module call. This makes configuration slightly more complicated, but can potentially reduce the amount of required tasks/YAML code. We can keep the - name: Name of Task
aix_chsec:
file: filename
stanzas:
- stanza1:
key1: value1
key2: value2
keyN: valueN
state: [ present|absent ]
- stanza2:
key1: value1
key2: value2
keyN: valueN
state: [ present|absent ]
backup: bool (default no, timestamped backup before making changes.)Real world use:
---
- hosts: targetserver
gather_facts: no
vars:
example_chsec:
- file: /etc/security/user
stanza: default
attrs:
logintimes: ":0800-1700"
- file: /etc/security/limits
stanzas:
- joe:
cpu: 3600
file: -1
- charlie:
cpu: 3600
remote_user: deploy
- tasks:
name: Example chsec
aix_chsec:
file: "{{ item.file }}"
stanza: "{{ item.stanza }}"
attrs: "{{ item.attrs }}"
loop:
- "{{ example_chsec }}"The example_chsec YAML above converts to the following JSON: {
"example_chsec": [
{
"file": "/etc/security/user",
"stanza": "default",
"attrs": {
"logintimes": ":0800-1700"
}
},
{
"file": "/etc/security/limits",
"stanzas": [
{
"joe": {
"cpu": 3600,
"file": -1
}
},
{
"charlie": {
"cpu": 3600
}
}
]
}
]
}Open Questions
|
| module.fail_json(msg='Failed to run chsec command (absent).', rc=rc, stdout=stdout, stderr=stderr) | ||
| else: | ||
| msg = 'stanza removed' | ||
| changed = True |
There was a problem hiding this comment.
Unless I am mistaken, this doesnt actually do anything. I do not believe it's possible to have an 'absent' flag to remove an entire stanza. chsec can only remove given attrs/options from a given stanza, it cannot remove the entire stanza.
This code block is just 'unsetting' all of the given attrs/options and ignoring the value assigned to them. These two YAML examples behave exactly the same way even though one has state=present and the other state=absent:
- name: Remove LDAP user stanzas
aix_chsec:
path: /etc/security/user
stanza: ldapuser
options: SYSTEM=LDAP,registry=LDAP
state: absent- name: Remove LDAP user stanzas
aix_chsec:
path: /etc/security/user
stanza: ldapuser
options: SYSTEM=,registry=
state: presentHOWEVER, if there are other attrs set on that user stanza, the stanza will still exist. You need to specify every single user attr/option on that stanza to remove the stanza. Adding a 'true' state=absent will mean going through the given file, finding the stanza, getting all of the key:value pairs in that stanza, and then running chsec key=null to every one of those.
That's a loooot more work.
|
closed in favour of #60976 |
SUMMARY
adds stanzas to aix config files using the chsec command.
ISSUE TYPE
COMPONENT NAME
aix_chsec
ADDITIONAL INFORMATION
example plays: