diff --git a/changelogs/fragments/74-hcloud_server-improve-error-message-images.yml b/changelogs/fragments/74-hcloud_server-improve-error-message-images.yml new file mode 100644 index 0000000..5d660f8 --- /dev/null +++ b/changelogs/fragments/74-hcloud_server-improve-error-message-images.yml @@ -0,0 +1,3 @@ +minor_changes: + - hcloud_server - improve the validation and error response for not existing images + - hcloud_server - improve the handling of deprecated images diff --git a/plugins/modules/hcloud_server.py b/plugins/modules/hcloud_server.py index dca81dc..85eb583 100644 --- a/plugins/modules/hcloud_server.py +++ b/plugins/modules/hcloud_server.py @@ -8,6 +8,8 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type +from dateutil import relativedelta + DOCUMENTATION = ''' --- module: hcloud_server @@ -86,6 +88,11 @@ options: - Power off the server if it is running on upgrade. type: bool default: no + allow_deprecated_image: + description: + - Allows the creation of servers with deprecated images. + type: bool + default: no user_data: description: - User Data to be passed to the server on creation. @@ -309,7 +316,6 @@ class AnsibleHcloudServer(Hcloud): self.module.fail_json(msg=e.message) def _create_server(self): - self.module.fail_on_missing_params( required_params=["name", "server_type", "image"] ) @@ -321,13 +327,8 @@ class AnsibleHcloudServer(Hcloud): ), "user_data": self.module.params.get("user_data"), "labels": self.module.params.get("labels"), + "image": self._get_image() } - image = self.client.images.get_by_name(self.module.params.get("image")) - if image is not None: - # When image name is not available look for id instead - params["image"] = image - else: - params["image"] = self.client.images.get_by_id(self.module.params.get("image")) if self.module.params.get("ssh_keys") is not None: params["ssh_keys"] = [ @@ -390,6 +391,32 @@ class AnsibleHcloudServer(Hcloud): self._mark_as_changed() self._get_server() + def _get_image(self): + image_resp = self.client.images.get_list(name=self.module.params.get("image"), include_deprecated=True) + images = getattr(image_resp, 'images') + image = None + if images is not None and len(images) > 0: + # If image name is not available look for id instead + image = images[0] + else: + try: + image = self.client.images.get_by_id(self.module.params.get("image")) + except: + self.module.fail_json(msg=f"Image {self.module.params.get('image')} was not found") + if image.deprecated is not None: + available_until = image.deprecated + relativedelta.relativedelta(months=3) + if self.module.params.get("allow_deprecated_image"): + self.module.warn( + f"You try to use a deprecated image. The image {image.name} will " + f"continue to be available until {available_until.strftime('%Y-%m-%d')}." + ) + else: + self.module.fail_json(msg=f"You try to use a deprecated image. The image {image.name} will " + f"continue to be available until {available_until.strftime('%Y-%m-%d')}. " + f"If you want to use this image use allow_deprecated_image=yes." + ) + return image + def _update_server(self): try: rescue_mode = self.module.params.get("rescue_mode") @@ -527,8 +554,8 @@ class AnsibleHcloudServer(Hcloud): ) try: if not self.module.check_mode: - self.client.servers.rebuild(self.hcloud_server, self.client.images.get_by_name( - self.module.params.get("image"))).wait_until_finished() + image = self._get_image() + self.client.servers.rebuild(self.hcloud_server, image).wait_until_finished() self._mark_as_changed() self._get_server() @@ -571,6 +598,7 @@ class AnsibleHcloudServer(Hcloud): backups={"type": "bool", "default": False}, upgrade_disk={"type": "bool", "default": False}, force_upgrade={"type": "bool", "default": False}, + allow_deprecated_image={"type": "bool", "default": False}, rescue_mode={"type": "str"}, delete_protection={"type": "bool"}, rebuild_protection={"type": "bool"}, diff --git a/tests/integration/targets/hcloud_server/tasks/main.yml b/tests/integration/targets/hcloud_server/tasks/main.yml index 4a9cb43..73acf79 100644 --- a/tests/integration/targets/hcloud_server/tasks/main.yml +++ b/tests/integration/targets/hcloud_server/tasks/main.yml @@ -20,6 +20,35 @@ that: - result is failed - 'result.msg == "missing required arguments: server_type, image"' +- name: test create server with not existing image + hcloud_server: + name: "{{ hcloud_server_name }}" + server_type: cx11 + image: my-not-existing-image-20.04 + state: present + register: result + ignore_errors: yes +- name: verify fail test create server with not existing image + assert: + that: + - result is failed + - 'result.msg == "Image my-not-existing-image-20.04 was not found"' + +# Temporary test case to test deprecated images. This test will fail when the ubuntu-16.04 image was removed +# feel free to remove this test then. +- name: test create server with deprecated image + hcloud_server: + name: "{{ hcloud_server_name }}" + server_type: cx11 + image: ubuntu-16.04 + state: present + register: result + ignore_errors: yes +- name: verify fail test create server deprecated image + assert: + that: + - result is failed + - 'result.msg == "You try to use a deprecated image. The image ubuntu-16.04 will continue to be available until 2021-06-24. If you want to use this image use allow_deprecated_image=yes."' - name: test create server with check mode hcloud_server: