diff --git a/changelogs/fragments/allow-selecting-a-resource-using-its-id.yaml b/changelogs/fragments/allow-selecting-a-resource-using-its-id.yaml new file mode 100644 index 0000000..8eb5f52 --- /dev/null +++ b/changelogs/fragments/allow-selecting-a-resource-using-its-id.yaml @@ -0,0 +1,8 @@ +minor_changes: + - hcloud_load_balancer_network - Allow selecting a `load_balancer` or `network` using its ID. + - hcloud_load_balancer_service - Allow selecting a `load_balancer` using its ID. + - hcloud_load_balancer_target - Allow selecting a `load_balancer` or `server` using its ID. + - hcloud_rdns - Allow selecting a `server`, `floating_ip`, `primary_ip` or `load_balancer` using its ID. + - hcloud_route - Allow selecting a `network` using its ID. + - hcloud_server_network - Allow selecting a `network` or `server` using its ID. + - hcloud_subnetwork - Allow selecting to a `network` using its ID. diff --git a/plugins/module_utils/hcloud.py b/plugins/module_utils/hcloud.py index 983e3b7..871c3c5 100644 --- a/plugins/module_utils/hcloud.py +++ b/plugins/module_utils/hcloud.py @@ -4,7 +4,7 @@ import traceback -from typing import Any, Dict, Optional +from typing import Any, Dict, Optional, Union from ansible.module_utils.basic import ( AnsibleModule as AnsibleModuleBase, @@ -91,6 +91,27 @@ class AnsibleHCloud: application_version=version, ) + def _client_get_by_name_or_id(self, resource: str, param: Union[str, int]): + """ + Get a resource by name, and if not found by its ID. + + :param resource: Name of the resource client that implements both `get_by_name` and `get_by_id` methods + :param param: Name or ID of the resource to query + """ + resource_client = getattr(self.client, resource) + + result = resource_client.get_by_name(param) + if result is not None: + return result + + # If the param is not a valid ID, prevent an unnecessary call to the API. + try: + int(param) + except ValueError: + self.module.fail_json(msg=f"resource ({resource.rstrip('s')}) does not exist: {param}") + + return resource_client.get_by_id(param) + def _mark_as_changed(self) -> None: self.result["changed"] = True diff --git a/plugins/modules/hcloud_load_balancer_network.py b/plugins/modules/hcloud_load_balancer_network.py index cb4a1ef..3c2f2f3 100644 --- a/plugins/modules/hcloud_load_balancer_network.py +++ b/plugins/modules/hcloud_load_balancer_network.py @@ -20,12 +20,12 @@ version_added: 0.1.0 options: network: description: - - The name of the Hetzner Cloud Networks. + - Name or ID of the Hetzner Cloud Networks. type: str required: true load_balancer: description: - - The name of the Hetzner Cloud Load Balancer. + - Name or ID of the Hetzner Cloud Load Balancer. type: str required: true ip: @@ -118,15 +118,14 @@ class AnsibleHCloudLoadBalancerNetwork(AnsibleHCloud): def _get_load_balancer_and_network(self): try: - network = self.module.params.get("network") - self.hcloud_network = self.client.networks.get_by_name(network) - if not self.hcloud_network: - self.module.fail_json(msg=f"Network does not exist: {network}") - - load_balancer_name = self.module.params.get("load_balancer") - self.hcloud_load_balancer = self.client.load_balancers.get_by_name(load_balancer_name) - if not self.hcloud_load_balancer: - self.module.fail_json(msg=f"Load balancer does not exist: {load_balancer_name}") + self.hcloud_network = self._client_get_by_name_or_id( + "networks", + self.module.params.get("network"), + ) + self.hcloud_load_balancer = self._client_get_by_name_or_id( + "load_balancers", + self.module.params.get("load_balancer"), + ) self.hcloud_load_balancer_network = None except HCloudException as exception: diff --git a/plugins/modules/hcloud_load_balancer_service.py b/plugins/modules/hcloud_load_balancer_service.py index e9233d4..e7be4ab 100644 --- a/plugins/modules/hcloud_load_balancer_service.py +++ b/plugins/modules/hcloud_load_balancer_service.py @@ -20,7 +20,7 @@ version_added: 0.1.0 options: load_balancer: description: - - The Name of the Hetzner Cloud Load Balancer the service belongs to + - Name or ID of the Hetzner Cloud Load Balancer the service belongs to type: str required: true listen_port: @@ -343,11 +343,10 @@ class AnsibleHCloudLoadBalancerService(AnsibleHCloud): def _get_load_balancer(self): try: - load_balancer_name = self.module.params.get("load_balancer") - self.hcloud_load_balancer = self.client.load_balancers.get_by_name(load_balancer_name) - if not self.hcloud_load_balancer: - self.module.fail_json(msg=f"Load balancer does not exist: {load_balancer_name}") - + self.hcloud_load_balancer = self._client_get_by_name_or_id( + "load_balancers", + self.module.params.get("load_balancer"), + ) self._get_load_balancer_service() except HCloudException as exception: self.fail_json_hcloud(exception) diff --git a/plugins/modules/hcloud_load_balancer_target.py b/plugins/modules/hcloud_load_balancer_target.py index 5186044..a920eb6 100644 --- a/plugins/modules/hcloud_load_balancer_target.py +++ b/plugins/modules/hcloud_load_balancer_target.py @@ -26,12 +26,12 @@ options: required: true load_balancer: description: - - The name of the Hetzner Cloud Load Balancer. + - Name or ID of the Hetzner Cloud Load Balancer. type: str required: true server: description: - - The name of the Hetzner Cloud Server. + - Name or ID of the Hetzner Cloud Server. - Required if I(type) is server type: str label_selector: @@ -175,16 +175,16 @@ class AnsibleHCloudLoadBalancerTarget(AnsibleHCloud): def _get_load_balancer_and_target(self): try: - load_balancer_name = self.module.params.get("load_balancer") - self.hcloud_load_balancer = self.client.load_balancers.get_by_name(load_balancer_name) - if not self.hcloud_load_balancer: - self.module.fail_json(msg=f"Load balancer does not exist: {load_balancer_name}") + self.hcloud_load_balancer = self._client_get_by_name_or_id( + "load_balancers", + self.module.params.get("load_balancer"), + ) if self.module.params.get("type") == "server": - server_name = self.module.params.get("server") - self.hcloud_server = self.client.servers.get_by_name(server_name) - if not self.hcloud_server: - self.module.fail_json(msg=f"Server not found: {server_name}") + self.hcloud_server = self._client_get_by_name_or_id( + "servers", + self.module.params.get("server"), + ) self.hcloud_load_balancer_target = None except HCloudException as exception: diff --git a/plugins/modules/hcloud_rdns.py b/plugins/modules/hcloud_rdns.py index ae17f70..a36ab09 100644 --- a/plugins/modules/hcloud_rdns.py +++ b/plugins/modules/hcloud_rdns.py @@ -20,19 +20,19 @@ author: options: server: description: - - The name of the Hetzner Cloud server you want to add the reverse DNS entry to. + - Name or ID of the Hetzner Cloud server you want to add the reverse DNS entry to. type: str floating_ip: description: - - The name of the Hetzner Cloud Floating IP you want to add the reverse DNS entry to. + - Name or ID of the Hetzner Cloud Floating IP you want to add the reverse DNS entry to. type: str primary_ip: description: - - The name of the Hetzner Cloud Primary IP you want to add the reverse DNS entry to. + - Name or ID of the Hetzner Cloud Primary IP you want to add the reverse DNS entry to. type: str load_balancer: description: - - The name of the Hetzner Cloud Load Balancer you want to add the reverse DNS entry to. + - Name or ID of the Hetzner Cloud Load Balancer you want to add the reverse DNS entry to. type: str ip_address: description: @@ -178,21 +178,25 @@ class AnsibleHCloudReverseDNS(AnsibleHCloud): def _get_resource(self): try: if self.module.params.get("server"): - self.hcloud_resource = self.client.servers.get_by_name(self.module.params.get("server")) - if self.hcloud_resource is None: - self.module.fail_json(msg="The selected server does not exist") + self.hcloud_resource = self._client_get_by_name_or_id( + "servers", + self.module.params.get("server"), + ) elif self.module.params.get("floating_ip"): - self.hcloud_resource = self.client.floating_ips.get_by_name(self.module.params.get("floating_ip")) - if self.hcloud_resource is None: - self.module.fail_json(msg="The selected Floating IP does not exist") + self.hcloud_resource = self._client_get_by_name_or_id( + "floating_ips", + self.module.params.get("floating_ip"), + ) elif self.module.params.get("primary_ip"): - self.hcloud_resource = self.client.primary_ips.get_by_name(self.module.params.get("primary_ip")) - if self.hcloud_resource is None: - self.module.fail_json(msg="The selected Floating IP does not exist") + self.hcloud_resource = self._client_get_by_name_or_id( + "primary_ips", + self.module.params.get("primary_ip"), + ) elif self.module.params.get("load_balancer"): - self.hcloud_resource = self.client.load_balancers.get_by_name(self.module.params.get("load_balancer")) - if self.hcloud_resource is None: - self.module.fail_json(msg="The selected Load Balancer does not exist") + self.hcloud_resource = self._client_get_by_name_or_id( + "load_balancers", + self.module.params.get("load_balancer"), + ) except HCloudException as exception: self.fail_json_hcloud(exception) diff --git a/plugins/modules/hcloud_route.py b/plugins/modules/hcloud_route.py index 03e8ba8..57a58a2 100644 --- a/plugins/modules/hcloud_route.py +++ b/plugins/modules/hcloud_route.py @@ -20,7 +20,7 @@ author: options: network: description: - - The name of the Hetzner Cloud Network. + - Name or ID of the Hetzner Cloud Network. type: str required: true destination: @@ -112,7 +112,10 @@ class AnsibleHCloudRoute(AnsibleHCloud): def _get_network(self): try: - self.hcloud_network = self.client.networks.get_by_name(self.module.params.get("network")) + self.hcloud_network = self._client_get_by_name_or_id( + "networks", + self.module.params.get("network"), + ) self.hcloud_route = None except HCloudException as exception: self.fail_json_hcloud(exception) diff --git a/plugins/modules/hcloud_server_network.py b/plugins/modules/hcloud_server_network.py index 3764adf..61e68c2 100644 --- a/plugins/modules/hcloud_server_network.py +++ b/plugins/modules/hcloud_server_network.py @@ -20,12 +20,12 @@ author: options: network: description: - - The name of the Hetzner Cloud Networks. + - Name or ID of the Hetzner Cloud Networks. type: str required: true server: description: - - The name of the Hetzner Cloud server. + - Name or ID of the Hetzner Cloud server. type: str required: true ip: @@ -140,8 +140,14 @@ class AnsibleHCloudServerNetwork(AnsibleHCloud): def _get_server_and_network(self): try: - self.hcloud_network = self.client.networks.get_by_name(self.module.params.get("network")) - self.hcloud_server = self.client.servers.get_by_name(self.module.params.get("server")) + self.hcloud_network = self._client_get_by_name_or_id( + "networks", + self.module.params.get("network"), + ) + self.hcloud_server = self._client_get_by_name_or_id( + "servers", + self.module.params.get("server"), + ) self.hcloud_server_network = None except HCloudException as exception: self.fail_json_hcloud(exception) diff --git a/plugins/modules/hcloud_subnetwork.py b/plugins/modules/hcloud_subnetwork.py index 3b9e6ea..c00c07c 100644 --- a/plugins/modules/hcloud_subnetwork.py +++ b/plugins/modules/hcloud_subnetwork.py @@ -20,7 +20,7 @@ author: options: network: description: - - The ID or Name of the Hetzner Cloud Networks. + - The name or ID of the Hetzner Cloud Networks. type: str required: true ip_range: @@ -152,7 +152,10 @@ class AnsibleHCloudSubnetwork(AnsibleHCloud): def _get_network(self): try: - self.hcloud_network = self.client.networks.get_by_name(self.module.params.get("network")) + self.hcloud_network = self._client_get_by_name_or_id( + "networks", + self.module.params.get("network"), + ) self.hcloud_subnetwork = None except HCloudException as exception: self.fail_json_hcloud(exception) diff --git a/tests/integration/targets/hcloud_load_balancer_network/tasks/test.yml b/tests/integration/targets/hcloud_load_balancer_network/tasks/test.yml index c468b5b..689853d 100644 --- a/tests/integration/targets/hcloud_load_balancer_network/tasks/test.yml +++ b/tests/integration/targets/hcloud_load_balancer_network/tasks/test.yml @@ -59,7 +59,7 @@ assert: that: - result is failed - - "result.msg == 'Load balancer does not exist: does-not-exist'" + - "result.msg == 'resource (load_balancer) does not exist: does-not-exist'" - name: test fail network does not exist hetzner.hcloud.hcloud_load_balancer_network: @@ -72,7 +72,7 @@ assert: that: - result is failed - - "result.msg == 'Network does not exist: does-not-exist'" + - "result.msg == 'resource (network) does not exist: does-not-exist'" - name: test create load_balancer network with checkmode hetzner.hcloud.hcloud_load_balancer_network: diff --git a/tests/integration/targets/hcloud_load_balancer_service/tasks/test.yml b/tests/integration/targets/hcloud_load_balancer_service/tasks/test.yml index 0ef6411..e7a6a83 100644 --- a/tests/integration/targets/hcloud_load_balancer_service/tasks/test.yml +++ b/tests/integration/targets/hcloud_load_balancer_service/tasks/test.yml @@ -25,7 +25,7 @@ assert: that: - result is failed - - "result.msg == 'Load balancer does not exist: does-not-exist'" + - "result.msg == 'resource (load_balancer) does not exist: does-not-exist'" - name: test create load_balancer service with checkmode hetzner.hcloud.hcloud_load_balancer_service: diff --git a/tests/integration/targets/hcloud_load_balancer_target/tasks/test.yml b/tests/integration/targets/hcloud_load_balancer_target/tasks/test.yml index c1c9093..ad9ae1f 100644 --- a/tests/integration/targets/hcloud_load_balancer_target/tasks/test.yml +++ b/tests/integration/targets/hcloud_load_balancer_target/tasks/test.yml @@ -37,7 +37,7 @@ assert: that: - result is failed - - "result.msg == 'Load balancer does not exist: does-not-exist'" + - "result.msg == 'resource (load_balancer) does not exist: does-not-exist'" - name: test fail server does not exist hetzner.hcloud.hcloud_load_balancer_target: @@ -50,7 +50,7 @@ assert: that: - result is failed - - "result.msg == 'Server not found: does-not-exist'" + - "result.msg == 'resource (server) does not exist: does-not-exist'" - name: test create load_balancer target with checkmode hetzner.hcloud.hcloud_load_balancer_target: diff --git a/tests/integration/targets/hcloud_rdns/tasks/test.yml b/tests/integration/targets/hcloud_rdns/tasks/test.yml index ca7ca53..e58478d 100644 --- a/tests/integration/targets/hcloud_rdns/tasks/test.yml +++ b/tests/integration/targets/hcloud_rdns/tasks/test.yml @@ -70,7 +70,7 @@ assert: that: - result is failed - - 'result.msg == "The selected server does not exist"' + - 'result.msg == "resource (server) does not exist: not-existing"' - name: test create rdns hetzner.hcloud.hcloud_rdns: server: "{{ hcloud_server_name }}"