We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Tower Settings of type on/off idempotency not working
### Please confirm the following

- [X] I agree to follow this project's [code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html).
- [X] I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.
- [X] I understand that AWX is open source software provided for free and that I might not receive a timely response.
- [X] I am **NOT** reporting a (potential) security vulnerability. (These should be emailed to `security@ansible.com` instead.)

### Bug Summary

When trying to set the setting named AWX_MOUNT_ISOLATED_PATHS_ON_K8S to true, no matter what I put in the playbook it is always marked as "changed: true", even if the setting is already true..

Sample Task:
```
    - name: SET AWX EXPOSE HOST PATHS
      awx.awx.settings:
        name: "AWX_MOUNT_ISOLATED_PATHS_ON_K8S"
        value: true

```

When I change the playbook value and register the results of the task to review the results I get this:

| Value In Playbook | Resulting Debug|
| ------- | ------- |
| true    | ok: [awxlab] => {<br>    "this_setting": {<br>        "changed": true,<br>        "failed": false,<br>        "new_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": "True"<br>        },<br>        "old_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": true<br>        },<br>        "value": true<br>    }<br>}|
| True    | ok: [awxlab] => {<br>    "this_setting": {<br>        "changed": true,<br>        "failed": false,<br>        "new_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": "True"<br>        },<br>        "old_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": true<br>        },<br>        "value": true<br>    }<br>}|
| "true"  | ok: [awxlab] => {<br>    "this_setting": {<br>        "changed": true,<br>        "failed": false,<br>        "new_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": "true"<br>        },<br>        "old_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": true<br>        },<br>        "value": true<br>    }<br>}|
| "True"  | ok: [awxlab] => {<br>    "this_setting": {<br>        "changed": true,<br>        "failed": false,<br>        "new_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": "True"<br>        },<br>        "old_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": true<br>        },<br>        "value": true<br>    }<br>}
| yes     | ok: [awxlab] => {<br>    "this_setting": {<br>        "changed": true,<br>        "failed": false,<br>        "new_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": "True"<br>        },<br>        "old_values": {<br>            "AWX_MOUNT_ISOLATED_PATHS_ON_K8S": true<br>        },<br>        "value": true<br>    }<br>}


The documentation says this:
```> AWX.AWX.SETTINGS    ([...]collections/ansible_collections/awx/awx/plugins/modules/settings.py)

        Modify Automation Platform Controller settings. See https://www.ansible.com/tower for an overview.

OPTIONS (= is mandatory):
- value
        Value to be modified for given setting.
        **If given a non-string type, will make best effort to cast it to type API expects.**
        For better control over types, use the `settings' param instead.
        default: null
        type: str
```

This leads me to believe that the logic used to sanitize the input might be doing a little extra or the conversion of 'settings' parameters to/from name/value parameters.

The documentation does show an example of how to use both the settings parameter and the name/value parameter.  So, this may be lower priority but I wanted to get this somewhere that could be search by others who may be running into this issue.

### AWX version

23.1.0

### Select the relevant components

- [ ] UI
- [ ] UI (tech preview)
- [ ] API
- [ ] Docs
- [X] Collection
- [ ] CLI
- [ ] Other

### Installation method

kubernetes

### Modifications

no

### Ansible version

2.15.4

### Operating system

CentOS Stream release 9

### Web browser

Firefox

### Steps to reproduce

Use a playbook that modifies a boolean setting.
Use the awx.awx.setting module.
Use the name/value parameters instead of the settings paremeter.
Sample:
```
    - name: SET AWX EXPOSE HOST PATHS
      awx.awx.settings:
        name: "AWX_MOUNT_ISOLATED_PATHS_ON_K8S"
        value: true
      register: this_setting
    
    - name: Debug this setting
      debug: var=this_setting
```

### Expected results

When the setting is already true, idempotency keeps the playbook from trying to update the setting again.

### Actual results

Regardless if the setting is true or not, the playbook always updates the setting.

### Additional information

_No response_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `awx_collection/plugins/modules/settings.py`
Content:
```
1 #!/usr/bin/python
2 # coding: utf-8 -*-
3 
4 # (c) 2018, Nikhil Jain <nikjain@redhat.com>
5 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
6 
7 from __future__ import absolute_import, division, print_function
8 
9 __metaclass__ = type
10 
11 
12 ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
13 
14 
15 DOCUMENTATION = '''
16 ---
17 module: settings
18 author: "Nikhil Jain (@jainnikhil30)"
19 short_description: Modify Automation Platform Controller settings.
20 description:
21     - Modify Automation Platform Controller settings. See
22       U(https://www.ansible.com/tower) for an overview.
23 options:
24     name:
25       description:
26         - Name of setting to modify
27       type: str
28     value:
29       description:
30         - Value to be modified for given setting.
31         - If given a non-string type, will make best effort to cast it to type API expects.
32         - For better control over types, use the C(settings) param instead.
33       type: str
34     settings:
35       description:
36         - A data structure to be sent into the settings endpoint
37       type: dict
38 requirements:
39   - pyyaml
40 extends_documentation_fragment: awx.awx.auth
41 '''
42 
43 EXAMPLES = '''
44 - name: Set the value of AWX_ISOLATION_BASE_PATH
45   settings:
46     name: AWX_ISOLATION_BASE_PATH
47     value: "/tmp"
48   register: testing_settings
49 
50 - name: Set the value of AWX_ISOLATION_SHOW_PATHS
51   settings:
52     name: "AWX_ISOLATION_SHOW_PATHS"
53     value: "'/var/lib/awx/projects/', '/tmp'"
54   register: testing_settings
55 
56 - name: Set the LDAP Auth Bind Password
57   settings:
58     name: "AUTH_LDAP_BIND_PASSWORD"
59     value: "Password"
60   no_log: true
61 
62 - name: Set all the LDAP Auth Bind Params
63   settings:
64     settings:
65       AUTH_LDAP_BIND_PASSWORD: "password"
66       AUTH_LDAP_USER_ATTR_MAP:
67         email: "mail"
68         first_name: "givenName"
69         last_name: "surname"
70 '''
71 
72 from ..module_utils.controller_api import ControllerAPIModule
73 
74 try:
75     import yaml
76 
77     HAS_YAML = True
78 except ImportError:
79     HAS_YAML = False
80 
81 
82 def coerce_type(module, value):
83     # If our value is already None we can just return directly
84     if value is None:
85         return value
86 
87     yaml_ish = bool((value.startswith('{') and value.endswith('}')) or (value.startswith('[') and value.endswith(']')))
88     if yaml_ish:
89         if not HAS_YAML:
90             module.fail_json(msg="yaml is not installed, try 'pip install pyyaml'")
91         return yaml.safe_load(value)
92     elif value.lower in ('true', 'false', 't', 'f'):
93         return {'t': True, 'f': False}[value[0].lower()]
94     try:
95         return int(value)
96     except ValueError:
97         pass
98     return value
99 
100 
101 def main():
102     # Any additional arguments that are not fields of the item can be added here
103     argument_spec = dict(
104         name=dict(),
105         value=dict(),
106         settings=dict(type='dict'),
107     )
108 
109     # Create a module for ourselves
110     module = ControllerAPIModule(
111         argument_spec=argument_spec,
112         required_one_of=[['name', 'settings']],
113         mutually_exclusive=[['name', 'settings']],
114         required_if=[['name', 'present', ['value']]],
115     )
116 
117     # Extract our parameters
118     name = module.params.get('name')
119     value = module.params.get('value')
120     new_settings = module.params.get('settings')
121 
122     # If we were given a name/value pair we will just make settings out of that and proceed normally
123     if new_settings is None:
124         new_value = coerce_type(module, value)
125 
126         new_settings = {name: new_value}
127 
128     # Load the existing settings
129     existing_settings = module.get_endpoint('settings/all')['json']
130 
131     # Begin a json response
132     json_output = {'changed': False, 'old_values': {}, 'new_values': {}}
133 
134     # Check any of the settings to see if anything needs to be updated
135     needs_update = False
136     for a_setting in new_settings:
137         if a_setting not in existing_settings or existing_settings[a_setting] != new_settings[a_setting]:
138             # At least one thing is different so we need to patch
139             needs_update = True
140             json_output['old_values'][a_setting] = existing_settings[a_setting]
141             json_output['new_values'][a_setting] = new_settings[a_setting]
142 
143     if module._diff:
144         json_output['diff'] = {'before': json_output['old_values'], 'after': json_output['new_values']}
145 
146     # If nothing needs an update we can simply exit with the response (as not changed)
147     if not needs_update:
148         module.exit_json(**json_output)
149 
150     if module.check_mode and module._diff:
151         json_output['changed'] = True
152         module.exit_json(**json_output)
153 
154     # Make the call to update the settings
155     response = module.patch_endpoint('settings/all', **{'data': new_settings})
156 
157     if response['status_code'] == 200:
158         # Set the changed response to True
159         json_output['changed'] = True
160 
161         # To deal with the old style values we need to return 'value' in the response
162         new_values = {}
163         for a_setting in new_settings:
164             new_values[a_setting] = response['json'][a_setting]
165 
166         # If we were using a name we will just add a value of a string, otherwise we will return an array in values
167         if name is not None:
168             json_output['value'] = new_values[name]
169         else:
170             json_output['values'] = new_values
171 
172         module.exit_json(**json_output)
173     elif 'json' in response and '__all__' in response['json']:
174         module.fail_json(msg=response['json']['__all__'])
175     else:
176         module.fail_json(**{'msg': "Unable to update settings, see response", 'response': response})
177 
178 
179 if __name__ == '__main__':
180     main()
181
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/awx_collection/plugins/modules/settings.py b/awx_collection/plugins/modules/settings.py
--- a/awx_collection/plugins/modules/settings.py
+++ b/awx_collection/plugins/modules/settings.py
@@ -89,7 +89,7 @@
         if not HAS_YAML:
             module.fail_json(msg="yaml is not installed, try 'pip install pyyaml'")
         return yaml.safe_load(value)
-    elif value.lower in ('true', 'false', 't', 'f'):
+    elif value.lower() in ('true', 'false', 't', 'f'):
         return {'t': True, 'f': False}[value[0].lower()]
     try:
         return int(value)

{"golden_diff": "diff --git a/awx_collection/plugins/modules/settings.py b/awx_collection/plugins/modules/settings.py\n--- a/awx_collection/plugins/modules/settings.py\n+++ b/awx_collection/plugins/modules/settings.py\n@@ -89,7 +89,7 @@\n         if not HAS_YAML:\n             module.fail_json(msg=\"yaml is not installed, try 'pip install pyyaml'\")\n         return yaml.safe_load(value)\n-    elif value.lower in ('true', 'false', 't', 'f'):\n+    elif value.lower() in ('true', 'false', 't', 'f'):\n         return {'t': True, 'f': False}[value[0].lower()]\n     try:\n         return int(value)\n", "issue": "Tower Settings of type on/off idempotency not working\n### Please confirm the following\n\n- [X] I agree to follow this project's [code of conduct](https://docs.ansible.com/ansible/latest/community/code_of_conduct.html).\n- [X] I have checked the [current issues](https://github.com/ansible/awx/issues) for duplicates.\n- [X] I understand that AWX is open source software provided for free and that I might not receive a timely response.\n- [X] I am **NOT** reporting a (potential) security vulnerability. (These should be emailed to `security@ansible.com` instead.)\n\n### Bug Summary\n\nWhen trying to set the setting named AWX_MOUNT_ISOLATED_PATHS_ON_K8S to true, no matter what I put in the playbook it is always marked as \"changed: true\", even if the setting is already true..\r\n\r\nSample Task:\r\n```\r\n    - name: SET AWX EXPOSE HOST PATHS\r\n      awx.awx.settings:\r\n        name: \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\"\r\n        value: true\r\n\r\n```\r\n\r\nWhen I change the playbook value and register the results of the task to review the results I get this:\r\n\r\n| Value In Playbook | Resulting Debug|\r\n| ------- | ------- |\r\n| true    | ok: [awxlab] => {<br>    \"this_setting\": {<br>        \"changed\": true,<br>        \"failed\": false,<br>        \"new_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": \"True\"<br>        },<br>        \"old_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": true<br>        },<br>        \"value\": true<br>    }<br>}|\r\n| True    | ok: [awxlab] => {<br>    \"this_setting\": {<br>        \"changed\": true,<br>        \"failed\": false,<br>        \"new_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": \"True\"<br>        },<br>        \"old_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": true<br>        },<br>        \"value\": true<br>    }<br>}|\r\n| \"true\"  | ok: [awxlab] => {<br>    \"this_setting\": {<br>        \"changed\": true,<br>        \"failed\": false,<br>        \"new_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": \"true\"<br>        },<br>        \"old_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": true<br>        },<br>        \"value\": true<br>    }<br>}|\r\n| \"True\"  | ok: [awxlab] => {<br>    \"this_setting\": {<br>        \"changed\": true,<br>        \"failed\": false,<br>        \"new_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": \"True\"<br>        },<br>        \"old_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": true<br>        },<br>        \"value\": true<br>    }<br>}\r\n| yes     | ok: [awxlab] => {<br>    \"this_setting\": {<br>        \"changed\": true,<br>        \"failed\": false,<br>        \"new_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": \"True\"<br>        },<br>        \"old_values\": {<br>            \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\": true<br>        },<br>        \"value\": true<br>    }<br>}\r\n\r\n\r\nThe documentation says this:\r\n```> AWX.AWX.SETTINGS    ([...]collections/ansible_collections/awx/awx/plugins/modules/settings.py)\r\n\r\n        Modify Automation Platform Controller settings. See https://www.ansible.com/tower for an overview.\r\n\r\nOPTIONS (= is mandatory):\r\n- value\r\n        Value to be modified for given setting.\r\n        **If given a non-string type, will make best effort to cast it to type API expects.**\r\n        For better control over types, use the `settings' param instead.\r\n        default: null\r\n        type: str\r\n```\r\n\r\nThis leads me to believe that the logic used to sanitize the input might be doing a little extra or the conversion of 'settings' parameters to/from name/value parameters.\r\n\r\nThe documentation does show an example of how to use both the settings parameter and the name/value parameter.  So, this may be lower priority but I wanted to get this somewhere that could be search by others who may be running into this issue.\n\n### AWX version\n\n23.1.0\n\n### Select the relevant components\n\n- [ ] UI\n- [ ] UI (tech preview)\n- [ ] API\n- [ ] Docs\n- [X] Collection\n- [ ] CLI\n- [ ] Other\n\n### Installation method\n\nkubernetes\n\n### Modifications\n\nno\n\n### Ansible version\n\n2.15.4\n\n### Operating system\n\nCentOS Stream release 9\n\n### Web browser\n\nFirefox\n\n### Steps to reproduce\n\nUse a playbook that modifies a boolean setting.\r\nUse the awx.awx.setting module.\r\nUse the name/value parameters instead of the settings paremeter.\r\nSample:\r\n```\r\n    - name: SET AWX EXPOSE HOST PATHS\r\n      awx.awx.settings:\r\n        name: \"AWX_MOUNT_ISOLATED_PATHS_ON_K8S\"\r\n        value: true\r\n      register: this_setting\r\n    \r\n    - name: Debug this setting\r\n      debug: var=this_setting\r\n```\n\n### Expected results\n\nWhen the setting is already true, idempotency keeps the playbook from trying to update the setting again.\n\n### Actual results\n\nRegardless if the setting is true or not, the playbook always updates the setting.\n\n### Additional information\n\n_No response_\n", "before_files": [{"content": "#!/usr/bin/python\n# coding: utf-8 -*-\n\n# (c) 2018, Nikhil Jain <nikjain@redhat.com>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: settings\nauthor: \"Nikhil Jain (@jainnikhil30)\"\nshort_description: Modify Automation Platform Controller settings.\ndescription:\n    - Modify Automation Platform Controller settings. See\n      U(https://www.ansible.com/tower) for an overview.\noptions:\n    name:\n      description:\n        - Name of setting to modify\n      type: str\n    value:\n      description:\n        - Value to be modified for given setting.\n        - If given a non-string type, will make best effort to cast it to type API expects.\n        - For better control over types, use the C(settings) param instead.\n      type: str\n    settings:\n      description:\n        - A data structure to be sent into the settings endpoint\n      type: dict\nrequirements:\n  - pyyaml\nextends_documentation_fragment: awx.awx.auth\n'''\n\nEXAMPLES = '''\n- name: Set the value of AWX_ISOLATION_BASE_PATH\n  settings:\n    name: AWX_ISOLATION_BASE_PATH\n    value: \"/tmp\"\n  register: testing_settings\n\n- name: Set the value of AWX_ISOLATION_SHOW_PATHS\n  settings:\n    name: \"AWX_ISOLATION_SHOW_PATHS\"\n    value: \"'/var/lib/awx/projects/', '/tmp'\"\n  register: testing_settings\n\n- name: Set the LDAP Auth Bind Password\n  settings:\n    name: \"AUTH_LDAP_BIND_PASSWORD\"\n    value: \"Password\"\n  no_log: true\n\n- name: Set all the LDAP Auth Bind Params\n  settings:\n    settings:\n      AUTH_LDAP_BIND_PASSWORD: \"password\"\n      AUTH_LDAP_USER_ATTR_MAP:\n        email: \"mail\"\n        first_name: \"givenName\"\n        last_name: \"surname\"\n'''\n\nfrom ..module_utils.controller_api import ControllerAPIModule\n\ntry:\n    import yaml\n\n    HAS_YAML = True\nexcept ImportError:\n    HAS_YAML = False\n\n\ndef coerce_type(module, value):\n    # If our value is already None we can just return directly\n    if value is None:\n        return value\n\n    yaml_ish = bool((value.startswith('{') and value.endswith('}')) or (value.startswith('[') and value.endswith(']')))\n    if yaml_ish:\n        if not HAS_YAML:\n            module.fail_json(msg=\"yaml is not installed, try 'pip install pyyaml'\")\n        return yaml.safe_load(value)\n    elif value.lower in ('true', 'false', 't', 'f'):\n        return {'t': True, 'f': False}[value[0].lower()]\n    try:\n        return int(value)\n    except ValueError:\n        pass\n    return value\n\n\ndef main():\n    # Any additional arguments that are not fields of the item can be added here\n    argument_spec = dict(\n        name=dict(),\n        value=dict(),\n        settings=dict(type='dict'),\n    )\n\n    # Create a module for ourselves\n    module = ControllerAPIModule(\n        argument_spec=argument_spec,\n        required_one_of=[['name', 'settings']],\n        mutually_exclusive=[['name', 'settings']],\n        required_if=[['name', 'present', ['value']]],\n    )\n\n    # Extract our parameters\n    name = module.params.get('name')\n    value = module.params.get('value')\n    new_settings = module.params.get('settings')\n\n    # If we were given a name/value pair we will just make settings out of that and proceed normally\n    if new_settings is None:\n        new_value = coerce_type(module, value)\n\n        new_settings = {name: new_value}\n\n    # Load the existing settings\n    existing_settings = module.get_endpoint('settings/all')['json']\n\n    # Begin a json response\n    json_output = {'changed': False, 'old_values': {}, 'new_values': {}}\n\n    # Check any of the settings to see if anything needs to be updated\n    needs_update = False\n    for a_setting in new_settings:\n        if a_setting not in existing_settings or existing_settings[a_setting] != new_settings[a_setting]:\n            # At least one thing is different so we need to patch\n            needs_update = True\n            json_output['old_values'][a_setting] = existing_settings[a_setting]\n            json_output['new_values'][a_setting] = new_settings[a_setting]\n\n    if module._diff:\n        json_output['diff'] = {'before': json_output['old_values'], 'after': json_output['new_values']}\n\n    # If nothing needs an update we can simply exit with the response (as not changed)\n    if not needs_update:\n        module.exit_json(**json_output)\n\n    if module.check_mode and module._diff:\n        json_output['changed'] = True\n        module.exit_json(**json_output)\n\n    # Make the call to update the settings\n    response = module.patch_endpoint('settings/all', **{'data': new_settings})\n\n    if response['status_code'] == 200:\n        # Set the changed response to True\n        json_output['changed'] = True\n\n        # To deal with the old style values we need to return 'value' in the response\n        new_values = {}\n        for a_setting in new_settings:\n            new_values[a_setting] = response['json'][a_setting]\n\n        # If we were using a name we will just add a value of a string, otherwise we will return an array in values\n        if name is not None:\n            json_output['value'] = new_values[name]\n        else:\n            json_output['values'] = new_values\n\n        module.exit_json(**json_output)\n    elif 'json' in response and '__all__' in response['json']:\n        module.fail_json(msg=response['json']['__all__'])\n    else:\n        module.fail_json(**{'msg': \"Unable to update settings, see response\", 'response': response})\n\n\nif __name__ == '__main__':\n    main()\n", "path": "awx_collection/plugins/modules/settings.py"}], "after_files": [{"content": "#!/usr/bin/python\n# coding: utf-8 -*-\n\n# (c) 2018, Nikhil Jain <nikjain@redhat.com>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n\n__metaclass__ = type\n\n\nANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}\n\n\nDOCUMENTATION = '''\n---\nmodule: settings\nauthor: \"Nikhil Jain (@jainnikhil30)\"\nshort_description: Modify Automation Platform Controller settings.\ndescription:\n    - Modify Automation Platform Controller settings. See\n      U(https://www.ansible.com/tower) for an overview.\noptions:\n    name:\n      description:\n        - Name of setting to modify\n      type: str\n    value:\n      description:\n        - Value to be modified for given setting.\n        - If given a non-string type, will make best effort to cast it to type API expects.\n        - For better control over types, use the C(settings) param instead.\n      type: str\n    settings:\n      description:\n        - A data structure to be sent into the settings endpoint\n      type: dict\nrequirements:\n  - pyyaml\nextends_documentation_fragment: awx.awx.auth\n'''\n\nEXAMPLES = '''\n- name: Set the value of AWX_ISOLATION_BASE_PATH\n  settings:\n    name: AWX_ISOLATION_BASE_PATH\n    value: \"/tmp\"\n  register: testing_settings\n\n- name: Set the value of AWX_ISOLATION_SHOW_PATHS\n  settings:\n    name: \"AWX_ISOLATION_SHOW_PATHS\"\n    value: \"'/var/lib/awx/projects/', '/tmp'\"\n  register: testing_settings\n\n- name: Set the LDAP Auth Bind Password\n  settings:\n    name: \"AUTH_LDAP_BIND_PASSWORD\"\n    value: \"Password\"\n  no_log: true\n\n- name: Set all the LDAP Auth Bind Params\n  settings:\n    settings:\n      AUTH_LDAP_BIND_PASSWORD: \"password\"\n      AUTH_LDAP_USER_ATTR_MAP:\n        email: \"mail\"\n        first_name: \"givenName\"\n        last_name: \"surname\"\n'''\n\nfrom ..module_utils.controller_api import ControllerAPIModule\n\ntry:\n    import yaml\n\n    HAS_YAML = True\nexcept ImportError:\n    HAS_YAML = False\n\n\ndef coerce_type(module, value):\n    # If our value is already None we can just return directly\n    if value is None:\n        return value\n\n    yaml_ish = bool((value.startswith('{') and value.endswith('}')) or (value.startswith('[') and value.endswith(']')))\n    if yaml_ish:\n        if not HAS_YAML:\n            module.fail_json(msg=\"yaml is not installed, try 'pip install pyyaml'\")\n        return yaml.safe_load(value)\n    elif value.lower() in ('true', 'false', 't', 'f'):\n        return {'t': True, 'f': False}[value[0].lower()]\n    try:\n        return int(value)\n    except ValueError:\n        pass\n    return value\n\n\ndef main():\n    # Any additional arguments that are not fields of the item can be added here\n    argument_spec = dict(\n        name=dict(),\n        value=dict(),\n        settings=dict(type='dict'),\n    )\n\n    # Create a module for ourselves\n    module = ControllerAPIModule(\n        argument_spec=argument_spec,\n        required_one_of=[['name', 'settings']],\n        mutually_exclusive=[['name', 'settings']],\n        required_if=[['name', 'present', ['value']]],\n    )\n\n    # Extract our parameters\n    name = module.params.get('name')\n    value = module.params.get('value')\n    new_settings = module.params.get('settings')\n\n    # If we were given a name/value pair we will just make settings out of that and proceed normally\n    if new_settings is None:\n        new_value = coerce_type(module, value)\n\n        new_settings = {name: new_value}\n\n    # Load the existing settings\n    existing_settings = module.get_endpoint('settings/all')['json']\n\n    # Begin a json response\n    json_output = {'changed': False, 'old_values': {}, 'new_values': {}}\n\n    # Check any of the settings to see if anything needs to be updated\n    needs_update = False\n    for a_setting in new_settings:\n        if a_setting not in existing_settings or existing_settings[a_setting] != new_settings[a_setting]:\n            # At least one thing is different so we need to patch\n            needs_update = True\n            json_output['old_values'][a_setting] = existing_settings[a_setting]\n            json_output['new_values'][a_setting] = new_settings[a_setting]\n\n    if module._diff:\n        json_output['diff'] = {'before': json_output['old_values'], 'after': json_output['new_values']}\n\n    # If nothing needs an update we can simply exit with the response (as not changed)\n    if not needs_update:\n        module.exit_json(**json_output)\n\n    if module.check_mode and module._diff:\n        json_output['changed'] = True\n        module.exit_json(**json_output)\n\n    # Make the call to update the settings\n    response = module.patch_endpoint('settings/all', **{'data': new_settings})\n\n    if response['status_code'] == 200:\n        # Set the changed response to True\n        json_output['changed'] = True\n\n        # To deal with the old style values we need to return 'value' in the response\n        new_values = {}\n        for a_setting in new_settings:\n            new_values[a_setting] = response['json'][a_setting]\n\n        # If we were using a name we will just add a value of a string, otherwise we will return an array in values\n        if name is not None:\n            json_output['value'] = new_values[name]\n        else:\n            json_output['values'] = new_values\n\n        module.exit_json(**json_output)\n    elif 'json' in response and '__all__' in response['json']:\n        module.fail_json(msg=response['json']['__all__'])\n    else:\n        module.fail_json(**{'msg': \"Unable to update settings, see response\", 'response': response})\n\n\nif __name__ == '__main__':\n    main()\n", "path": "awx_collection/plugins/modules/settings.py"}]}