|
17 | 17 | description:
|
18 | 18 | - (Re)set the password for a storage box.
|
19 | 19 | extends_documentation_fragment:
|
| 20 | + - community.hrobot.api._robot_compat_shim # must come before api and robot |
| 21 | + - community.hrobot.api |
20 | 22 | - community.hrobot.robot
|
21 | 23 | - community.hrobot.attributes
|
| 24 | + - community.hrobot.attributes._actiongroup_robot_and_api # must come before the other two! |
| 25 | + - community.hrobot.attributes.actiongroup_api |
22 | 26 | - community.hrobot.attributes.actiongroup_robot
|
23 | 27 |
|
24 | 28 | attributes:
|
|
32 | 36 | - This module performs an action on every invocation.
|
33 | 37 |
|
34 | 38 | options:
|
| 39 | + hetzner_token: |
| 40 | + version_added: 2.5.0 |
35 | 41 | id:
|
36 | 42 | description:
|
37 | 43 | - The ID of the storage box to modify.
|
|
42 | 48 | - The new password for the storage box.
|
43 | 49 | - If not provided, a random password will be created by the Robot API
|
44 | 50 | and returned as RV(password).
|
| 51 | + - This option is required if O(hetzner_token) is provided, since the new API does not support setting (and returning) a random password. |
45 | 52 | type: str
|
46 | 53 | """
|
47 | 54 |
|
|
52 | 59 | id: 123
|
53 | 60 | password: "newpassword"
|
54 | 61 |
|
55 |
| -- name: Set a random password |
| 62 | +- name: Set a random password (only works with the legacy Robot API) |
56 | 63 | community.hrobot.storagebox_set_password:
|
57 | 64 | id: 123
|
58 | 65 | register: result
|
|
79 | 86 | from ansible_collections.community.hrobot.plugins.module_utils.robot import (
|
80 | 87 | BASE_URL,
|
81 | 88 | ROBOT_DEFAULT_ARGUMENT_SPEC,
|
| 89 | + _ROBOT_DEFAULT_ARGUMENT_SPEC_COMPAT, |
82 | 90 | fetch_url_json,
|
83 | 91 | )
|
84 | 92 |
|
| 93 | +from ansible_collections.community.hrobot.plugins.module_utils.api import ( |
| 94 | + API_BASE_URL, |
| 95 | + API_DEFAULT_ARGUMENT_SPEC, |
| 96 | + _API_DEFAULT_ARGUMENT_SPEC_COMPAT, |
| 97 | + ApplyActionError, |
| 98 | + api_apply_action, |
| 99 | +) |
| 100 | + |
85 | 101 |
|
86 | 102 | def main():
|
87 |
| - argument_spect = dict( |
| 103 | + argument_spec = dict( |
88 | 104 | id=dict(type="int", required=True),
|
89 | 105 | password=dict(type="str", no_log=True),
|
90 | 106 | )
|
91 |
| - argument_spect.update(ROBOT_DEFAULT_ARGUMENT_SPEC) |
92 |
| - module = AnsibleModule(argument_spect, supports_check_mode=False) |
| 107 | + argument_spec.update(ROBOT_DEFAULT_ARGUMENT_SPEC) |
| 108 | + argument_spec.update(_ROBOT_DEFAULT_ARGUMENT_SPEC_COMPAT) |
| 109 | + argument_spec.update(API_DEFAULT_ARGUMENT_SPEC) |
| 110 | + argument_spec.update(_API_DEFAULT_ARGUMENT_SPEC_COMPAT) |
| 111 | + module = AnsibleModule( |
| 112 | + argument_spec, |
| 113 | + supports_check_mode=False, |
| 114 | + required_by={"hetzner_token": "password"}, |
| 115 | + ) |
93 | 116 |
|
94 | 117 | id = module.params["id"]
|
95 | 118 | password = module.params.get("password")
|
96 | 119 |
|
97 |
| - url = "{0}/storagebox/{1}/password".format(BASE_URL, id) |
98 |
| - accepted_errors = ["STORAGEBOX_NOT_FOUND", "STORAGEBOX_INVALID_PASSWORD"] |
| 120 | + if module.params["hetzner_user"] is not None: |
| 121 | + # DEPRECATED: old API |
| 122 | + url = "{0}/storagebox/{1}/password".format(BASE_URL, id) |
| 123 | + accepted_errors = ["STORAGEBOX_NOT_FOUND", "STORAGEBOX_INVALID_PASSWORD"] |
99 | 124 |
|
100 |
| - if password: |
101 |
| - headers = {"Content-type": "application/x-www-form-urlencoded"} |
102 |
| - result, error = fetch_url_json( |
103 |
| - module, url, method="POST", accept_errors=accepted_errors, data=urlencode({"password": password}), headers=headers) |
104 |
| - else: |
105 |
| - result, error = fetch_url_json( |
106 |
| - module, url, method="POST", accept_errors=accepted_errors) |
| 125 | + if password: |
| 126 | + headers = {"Content-type": "application/x-www-form-urlencoded"} |
| 127 | + result, error = fetch_url_json( |
| 128 | + module, url, method="POST", accept_errors=accepted_errors, data=urlencode({"password": password}), headers=headers) |
| 129 | + else: |
| 130 | + result, error = fetch_url_json( |
| 131 | + module, url, method="POST", accept_errors=accepted_errors) |
| 132 | + |
| 133 | + if error == 'STORAGEBOX_NOT_FOUND': |
| 134 | + module.fail_json( |
| 135 | + msg='Storage Box with ID {0} not found'.format(id)) |
107 | 136 |
|
108 |
| - if error == 'STORAGEBOX_NOT_FOUND': |
109 |
| - module.fail_json( |
110 |
| - msg='Storage Box with ID {0} not found'.format(id)) |
| 137 | + if error == 'STORAGEBOX_INVALID_PASSWORD': |
| 138 | + module.fail_json( |
| 139 | + msg="The chosen password has been considered insecure or does not comply with Hetzner's password guideline") |
111 | 140 |
|
112 |
| - if error == 'STORAGEBOX_INVALID_PASSWORD': |
113 |
| - module.fail_json( |
114 |
| - msg="The chosen password has been considered insecure or does not comply with Hetzner's password guideline") |
| 141 | + module.exit_json(changed=True, password=result["password"]) |
115 | 142 |
|
116 |
| - module.exit_json(changed=True, password=result["password"]) |
| 143 | + else: |
| 144 | + # NEW API! |
| 145 | + action_url = "{0}/v1/storage_boxes/{1}/actions/reset_password".format(API_BASE_URL, id) |
| 146 | + action = { |
| 147 | + "password": password, |
| 148 | + } |
| 149 | + try: |
| 150 | + error = api_apply_action( |
| 151 | + module, |
| 152 | + action_url, |
| 153 | + action, |
| 154 | + lambda action_id: "{0}/v1/storage_boxes/actions/{1}".format(API_BASE_URL, action_id), |
| 155 | + check_done_delay=1, |
| 156 | + check_done_timeout=60, |
| 157 | + accept_errors=["not_found"], |
| 158 | + ) |
| 159 | + except ApplyActionError as exc: |
| 160 | + module.fail_json(msg='Error while resetting password: {0}'.format(exc)) |
| 161 | + |
| 162 | + if error == "not_found": |
| 163 | + module.fail_json(msg='Storage Box with ID {0} not found'.format(id)) |
| 164 | + |
| 165 | + module.exit_json(changed=True, password=password) |
117 | 166 |
|
118 | 167 |
|
119 | 168 | if __name__ == '__main__': # pragma: no cover
|
|
0 commit comments