diff --git a/changelogs/fragments/74601-ini-lookup-add-case-sensitive.yml b/changelogs/fragments/74601-ini-lookup-add-case-sensitive.yml new file mode 100644 index 00000000000..e870d90b2de --- /dev/null +++ b/changelogs/fragments/74601-ini-lookup-add-case-sensitive.yml @@ -0,0 +1,2 @@ +minor_changes: + - ini lookup - add case sensitive option (https://github.com/ansible/ansible/issues/74601) diff --git a/lib/ansible/plugins/lookup/ini.py b/lib/ansible/plugins/lookup/ini.py index eff6413dead..43b29eb643a 100644 --- a/lib/ansible/plugins/lookup/ini.py +++ b/lib/ansible/plugins/lookup/ini.py @@ -37,6 +37,12 @@ DOCUMENTATION = """ default: description: Return value if the key is not in the ini file. default: '' + case_sensitive: + description: + Whether key names read from C(file) should be case sensitive. This prevents + duplicate key errors if keys only differ in case. + default: False + version_added: '2.12' """ EXAMPLES = """ @@ -122,6 +128,8 @@ class LookupModule(LookupBase): paramvals = self.get_options() self.cp = configparser.ConfigParser() + if paramvals['case_sensitive']: + self.cp.optionxform = to_native ret = [] for term in terms: diff --git a/test/integration/targets/lookup_ini/lookup_case_check.properties b/test/integration/targets/lookup_ini/lookup_case_check.properties new file mode 100644 index 00000000000..ed3faaf88e1 --- /dev/null +++ b/test/integration/targets/lookup_ini/lookup_case_check.properties @@ -0,0 +1,2 @@ +name = captain +NAME = fantastic diff --git a/test/integration/targets/lookup_ini/runme.sh b/test/integration/targets/lookup_ini/runme.sh index 76f836a9b96..6f44332be9b 100755 --- a/test/integration/targets/lookup_ini/runme.sh +++ b/test/integration/targets/lookup_ini/runme.sh @@ -2,5 +2,4 @@ set -eux -ansible-playbook test_lookup_properties.yml -i inventory -v "$@" -ansible-playbook test_errors.yml -i inventory -v "$@" +ansible-playbook test_ini.yml -i inventory -v "$@" diff --git a/test/integration/targets/lookup_ini/test_case_sensitive.yml b/test/integration/targets/lookup_ini/test_case_sensitive.yml new file mode 100644 index 00000000000..f66674cabe6 --- /dev/null +++ b/test/integration/targets/lookup_ini/test_case_sensitive.yml @@ -0,0 +1,31 @@ +- name: Test case sensitive option + hosts: all + + tasks: + - name: Lookup a file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'name', file='duplicate_case_check.ini', section='reggae', case_sensitive=True) }}" + register: duplicate_case_sensitive_name + + - name: Lookup a file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'NAME', file='duplicate_case_check.ini', section='reggae', case_sensitive=True) }}" + register: duplicate_case_sensitive_NAME + + - name: Lookup a properties file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'name', file='lookup_case_check.properties', type='properties', case_sensitive=True) }}" + register: duplicate_case_sensitive_properties_name + + - name: Lookup a properties file with keys that differ only in case with case sensitivity enabled + debug: + msg: "{{ lookup('ini', 'NAME', file='lookup_case_check.properties', type='properties', case_sensitive=True) }}" + register: duplicate_case_sensitive_properties_NAME + + - name: Ensure the correct case-sensitive values were retieved + assert: + that: + - duplicate_case_sensitive_name.msg == 'bob' + - duplicate_case_sensitive_NAME.msg == 'marley' + - duplicate_case_sensitive_properties_name.msg == 'captain' + - duplicate_case_sensitive_properties_NAME.msg == 'fantastic' diff --git a/test/integration/targets/lookup_ini/test_errors.yml b/test/integration/targets/lookup_ini/test_errors.yml index 07962202301..c1832a354db 100644 --- a/test/integration/targets/lookup_ini/test_errors.yml +++ b/test/integration/targets/lookup_ini/test_errors.yml @@ -7,17 +7,17 @@ block: - name: Lookup a file with duplicate keys debug: - msg: "{{ lookup('ini', 'reggae', file='duplicate.ini', section='reggae') }}" + msg: "{{ lookup('ini', 'name', file='duplicate.ini', section='reggae') }}" ignore_errors: yes register: duplicate - name: Lookup a file with keys that differ only in case debug: - msg: "{{ lookup('ini', 'reggae', file='duplicate_case_check.ini', section='reggae') }}" + msg: "{{ lookup('ini', 'name', file='duplicate_case_check.ini', section='reggae') }}" ignore_errors: yes register: duplicate_case_sensitive - - name: Ensure duplicate key errers were handled properly + - name: Ensure duplicate key errors were handled properly assert: that: - duplicate is failed @@ -27,7 +27,7 @@ - name: Lookup a file with a missing section debug: - msg: "{{ lookup('ini', 'reggae', file='lookup.ini', section='missing') }}" + msg: "{{ lookup('ini', 'name', file='lookup.ini', section='missing') }}" ignore_errors: yes register: missing_section @@ -48,3 +48,15 @@ that: - bad_mojo is failed - '"No key to lookup was provided as first term with in string inline option" in bad_mojo.msg' + + - name: Test invalid option + debug: + msg: "{{ lookup('ini', 'invalid=option') }}" + ignore_errors: yes + register: invalid_option + + - name: Ensure invalid option failed + assert: + that: + - invalid_option is failed + - "'is not a valid option' in invalid_option.msg" diff --git a/test/integration/targets/lookup_ini/test_ini.yml b/test/integration/targets/lookup_ini/test_ini.yml new file mode 100644 index 00000000000..0d64e7db36c --- /dev/null +++ b/test/integration/targets/lookup_ini/test_ini.yml @@ -0,0 +1,3 @@ +- import_playbook: test_lookup_properties.yml +- import_playbook: test_errors.yml +- import_playbook: test_case_sensitive.yml