Migrated to hetzner.hcloud

pull/68298/head
Ansible Core Team 5 years ago committed by Matt Martz
parent 36a545553e
commit dd5a8dec21

@ -1,63 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.ansible_release import __version__
from ansible.module_utils.basic import env_fallback, missing_required_lib
try:
import hcloud
HAS_HCLOUD = True
except ImportError:
HAS_HCLOUD = False
class Hcloud(object):
def __init__(self, module, represent):
self.module = module
self.represent = represent
self.result = {"changed": False, self.represent: None}
if not HAS_HCLOUD:
module.fail_json(msg=missing_required_lib("hcloud-python"))
self._build_client()
def _build_client(self):
self.client = hcloud.Client(
token=self.module.params["api_token"],
api_endpoint=self.module.params["endpoint"],
application_name="ansible-module",
application_version=__version__,
)
def _mark_as_changed(self):
self.result["changed"] = True
@staticmethod
def base_module_arguments():
return {
"api_token": {
"type": "str",
"required": True,
"fallback": (env_fallback, ["HCLOUD_TOKEN"]),
"no_log": True,
},
"endpoint": {"type": "str", "default": "https://api.hetzner.cloud/v1"},
}
def _prepare_result(self):
"""Prepare the result for every module
:return: dict
"""
return {}
def get_result(self):
if getattr(self, self.represent) is not None:
self.result[self.represent] = self._prepare_result()
return self.result

@ -1,170 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_datacenter_info
short_description: Gather info about the Hetzner Cloud datacenters.
version_added: "2.8"
description:
- Gather info about your Hetzner Cloud datacenters.
- This module was called C(hcloud_datacenter_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_datacenter_facts).
Note that the M(hcloud_datacenter_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_datacenter_info)!
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the datacenter you want to get.
type: int
name:
description:
- The name of the datacenter you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud datacenter info
hcloud_datacenter_info:
register: output
- name: Print the gathered info
debug:
var: output
"""
RETURN = """
hcloud_datacenter_info:
description:
- The datacenter info as list
- This module was called C(hcloud_datacenter_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_datacenter_facts).
Note that the M(hcloud_datacenter_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_datacenter_info)!
returned: always
type: complex
contains:
id:
description: Numeric identifier of the datacenter
returned: always
type: int
sample: 1937415
name:
description: Name of the datacenter
returned: always
type: str
sample: fsn1-dc8
description:
description: Detail description of the datacenter
returned: always
type: str
sample: Falkenstein DC 8
location:
description: Name of the location where the datacenter resides in
returned: always
type: str
sample: fsn1
city:
description: City of the location
returned: always
type: str
sample: fsn1
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudDatacenterInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_datacenter_info")
self.hcloud_datacenter_info = None
def _prepare_result(self):
tmp = []
for datacenter in self.hcloud_datacenter_info:
if datacenter is not None:
tmp.append({
"id": to_native(datacenter.id),
"name": to_native(datacenter.name),
"description": to_native(datacenter.description),
"location": to_native(datacenter.location.name)
})
return tmp
def get_datacenters(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_datacenter_info = [self.client.datacenters.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_datacenter_info = [self.client.datacenters.get_by_name(
self.module.params.get("name")
)]
else:
self.hcloud_datacenter_info = self.client.datacenters.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudDatacenterInfo.define_module()
is_old_facts = module._name == 'hcloud_datacenter_facts'
if is_old_facts:
module.deprecate("The 'hcloud_datacenter_facts' module has been renamed to 'hcloud_datacenter_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudDatacenterInfo(module)
hcloud.get_datacenters()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_datacenter_facts': result['hcloud_datacenter_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_datacenter_info': result['hcloud_datacenter_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,353 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_floating_ip
short_description: Create and manage cloud Floating IPs on the Hetzner Cloud.
version_added: "2.10"
description:
- Create, update and manage cloud Floating IPs on the Hetzner Cloud.
author:
- Lukas Kaemmerling (@lkaemmerling)
options:
id:
description:
- The ID of the Hetzner Cloud Floating IPs to manage.
- Only required if no Floating IP I(name) is given.
type: int
name:
description:
- The Name of the Hetzner Cloud Floating IPs to manage.
- Only required if no Floating IP I(id) is given or a Floating IP does not exists.
type: str
description:
description:
- The Description of the Hetzner Cloud Floating IPs.
type: str
home_location:
description:
- Home Location of the Hetzner Cloud Floating IP.
- Required if no I(server) is given and Floating IP does not exists.
type: str
server:
description:
- Server Name the Floating IP should be assigned to.
- Required if no I(home_location) is given and Floating IP does not exists.
type: str
type:
description:
- Type of the Floating IP.
- Required if Floating IP does not exists
choices: [ ipv4, ipv6 ]
type: str
force:
description:
- Force the assignment or deletion of the Floating IP.
type: bool
delete_protection:
description:
- Protect the Floating IP for deletion.
type: bool
version_added: "2.10"
labels:
description:
- User-defined labels (key-value pairs).
type: dict
state:
description:
- State of the Floating IP.
default: present
choices: [ absent, present ]
type: str
requirements:
- hcloud-python >= 1.6.0
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a basic IPv4 Floating IP
hcloud_floating_ip:
name: my-floating-ip
home_location: fsn1
type: ipv4
state: present
- name: Create a basic IPv6 Floating IP
hcloud_floating_ip:
name: my-floating-ip
home_location: fsn1
type: ipv6
state: present
- name: Assign a Floating IP to a server
hcloud_floating_ip:
name: my-floating-ip
server: 1234
state: present
- name: Assign a Floating IP to another server
hcloud_floating_ip:
name: my-floating-ip
server: 1234
force: yes
state: present
- name: Floating IP should be absent
hcloud_floating_ip:
name: my-floating-ip
state: absent
"""
RETURN = """
hcloud_floating_ip:
description: The Floating IP instance
returned: Always
type: complex
contains:
id:
description: ID of the Floating IP
type: int
returned: Always
sample: 12345
name:
description: Name of the Floating IP
type: str
returned: Always
sample: my-floating-ip
description:
description: Description of the Floating IP
type: str
returned: Always
sample: my-floating-ip
ip:
description: IP Address of the Floating IP
type: str
returned: Always
sample: 116.203.104.109
type:
description: Type of the Floating IP
type: str
returned: Always
sample: ipv4
home_location:
description: Name of the home location of the Floating IP
type: str
returned: Always
sample: fsn1
server:
description: Name of the server the Floating IP is assigned to.
type: str
returned: Always
sample: "my-server"
delete_protection:
description: True if Floating IP is protected for deletion
type: bool
returned: always
sample: false
version_added: "2.10"
labels:
description: User-defined labels (key-value pairs)
type: dict
returned: Always
sample:
key: value
mylabel: 123
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
APIException = None
class AnsibleHcloudFloatingIP(Hcloud):
def __init__(self, module):
super(AnsibleHcloudFloatingIP, self).__init__(module, "hcloud_floating_ip")
self.hcloud_floating_ip = None
def _prepare_result(self):
server = None
if self.hcloud_floating_ip.server is not None:
server = to_native(self.hcloud_floating_ip.server.name)
return {
"id": to_native(self.hcloud_floating_ip.id),
"name": to_native(self.hcloud_floating_ip.name),
"description": to_native(self.hcloud_floating_ip.description),
"ip": to_native(self.hcloud_floating_ip.ip),
"type": to_native(self.hcloud_floating_ip.type),
"home_location": to_native(self.hcloud_floating_ip.home_location.name),
"labels": self.hcloud_floating_ip.labels,
"server": server,
"delete_protection": self.hcloud_floating_ip.protection["delete"],
}
def _get_floating_ip(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_floating_ip = self.client.floating_ips.get_by_id(
self.module.params.get("id")
)
else:
self.hcloud_floating_ip = self.client.floating_ips.get_by_name(
self.module.params.get("name")
)
except APIException as e:
self.module.fail_json(msg=e.message)
def _create_floating_ip(self):
self.module.fail_on_missing_params(
required_params=["type"]
)
params = {
"description": self.module.params.get("description"),
"type": self.module.params.get("type"),
"name": self.module.params.get("name"),
}
if self.module.params.get("home_location") is not None:
params["home_location"] = self.client.locations.get_by_name(
self.module.params.get("home_location")
)
elif self.module.params.get("server") is not None:
params["server"] = self.client.servers.get_by_name(
self.module.params.get("server")
)
else:
self.module.fail_json(msg="one of the following is required: home_location, server")
if self.module.params.get("labels") is not None:
params["labels"] = self.module.params.get("labels")
if not self.module.check_mode:
resp = self.client.floating_ips.create(**params)
self.hcloud_floating_ip = resp.floating_ip
self._mark_as_changed()
self._get_floating_ip()
def _update_floating_ip(self):
try:
labels = self.module.params.get("labels")
if labels is not None and labels != self.hcloud_floating_ip.labels:
if not self.module.check_mode:
self.hcloud_floating_ip.update(labels=labels)
self._mark_as_changed()
description = self.module.params.get("description")
if description is not None and description != self.hcloud_floating_ip.description:
if not self.module.check_mode:
self.hcloud_floating_ip.update(description=description)
self._mark_as_changed()
server = self.module.params.get("server")
if server is not None:
if self.module.params.get("force") or self.hcloud_floating_ip.server is None:
if not self.module.check_mode:
self.hcloud_floating_ip.assign(
self.client.servers.get_by_name(self.module.params.get("server"))
)
else:
self.module.warn(
"Floating IP is already assigned to server %s. You need to unassign the Floating IP or use force=yes."
% self.hcloud_floating_ip.server.name
)
self._mark_as_changed()
elif server is None and self.hcloud_floating_ip.server is not None:
if not self.module.check_mode:
self.hcloud_floating_ip.unassign()
self._mark_as_changed()
delete_protection = self.module.params.get("delete_protection")
if delete_protection is not None and delete_protection != self.hcloud_floating_ip.protection["delete"]:
if not self.module.check_mode:
self.hcloud_floating_ip.change_protection(delete=delete_protection).wait_until_finished()
self._mark_as_changed()
self._get_floating_ip()
except APIException as e:
self.module.fail_json(msg=e.message)
def present_floating_ip(self):
self._get_floating_ip()
if self.hcloud_floating_ip is None:
self._create_floating_ip()
else:
self._update_floating_ip()
def delete_floating_ip(self):
try:
self._get_floating_ip()
if self.hcloud_floating_ip is not None:
if self.module.params.get("force") or self.hcloud_floating_ip.server is None:
if not self.module.check_mode:
self.client.floating_ips.delete(self.hcloud_floating_ip)
else:
self.module.warn(
"Floating IP is currently assigned to server %s. You need to unassign the Floating IP or use force=yes."
% self.hcloud_floating_ip.server.name
)
self._mark_as_changed()
self.hcloud_floating_ip = None
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
description={"type": "str"},
server={"type": "str"},
home_location={"type": "str"},
force={"type": "bool"},
type={"choices": ["ipv4", "ipv6"]},
labels={"type": "dict"},
delete_protection={"type": "bool"},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
required_one_of=[['id', 'name']],
mutually_exclusive=[['home_location', 'server']],
supports_check_mode=True,
)
def main():
module = AnsibleHcloudFloatingIP.define_module()
hcloud = AnsibleHcloudFloatingIP(module)
state = module.params["state"]
if state == "absent":
hcloud.delete_floating_ip()
elif state == "present":
hcloud.present_floating_ip()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,195 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_floating_ip_info
short_description: Gather infos about the Hetzner Cloud Floating IPs.
version_added: "2.8"
description:
- Gather facts about your Hetzner Cloud Floating IPs.
- This module was called C(hcloud_floating_ip_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_floating_ip_facts).
Note that the M(hcloud_floating_ip_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_floating_ip_info)!
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the Floating IP you want to get.
type: int
label_selector:
description:
- The label selector for the Floating IP you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud Floating ip infos
hcloud_floating_ip_info:
register: output
- name: Print the gathered infos
debug:
var: output
"""
RETURN = """
hcloud_floating_ip_info:
description: The Floating ip infos as list
returned: always
type: complex
contains:
id:
description: Numeric identifier of the Floating IP
returned: always
type: int
sample: 1937415
name:
description: Name of the Floating IP
returned: Always
type: str
sample: my-floating-ip
version_added: "2.10"
description:
description: Description of the Floating IP
returned: always
type: str
sample: Falkenstein DC 8
ip:
description: IP address of the Floating IP
returned: always
type: str
sample: 131.232.99.1
type:
description: Type of the Floating IP
returned: always
type: str
sample: ipv4
server:
description: Name of the server where the Floating IP is assigned to.
returned: always
type: str
sample: my-server
home_location:
description: Location the Floating IP was created in
returned: always
type: str
sample: fsn1
delete_protection:
description: True if the Floating IP is protected for deletion
returned: always
type: bool
version_added: "2.10"
labels:
description: User-defined labels (key-value pairs)
returned: always
type: dict
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudFloatingIPInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_floating_ip_info")
self.hcloud_floating_ip_info = None
def _prepare_result(self):
tmp = []
for floating_ip in self.hcloud_floating_ip_info:
if floating_ip is not None:
server_name = None
if floating_ip.server is not None:
server_name = floating_ip.server.name
tmp.append({
"id": to_native(floating_ip.id),
"name": to_native(floating_ip.name),
"description": to_native(floating_ip.description),
"ip": to_native(floating_ip.ip),
"type": to_native(floating_ip.type),
"server": to_native(server_name),
"home_location": to_native(floating_ip.home_location.name),
"labels": floating_ip.labels,
"delete_protection": floating_ip.protection["delete"],
})
return tmp
def get_floating_ips(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_floating_ip_info = [self.client.floating_ips.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("label_selector") is not None:
self.hcloud_floating_ip_info = self.client.floating_ips.get_all(
label_selector=self.module.params.get("label_selector"))
else:
self.hcloud_floating_ip_info = self.client.floating_ips.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
label_selector={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudFloatingIPInfo.define_module()
is_old_facts = module._name == 'hcloud_floating_ip_facts'
if is_old_facts:
module.deprecate("The 'hcloud_floating_ip_facts' module has been renamed to 'hcloud_floating_ip_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudFloatingIPInfo(module)
hcloud.get_floating_ips()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_floating_ip_facts': result['hcloud_floating_ip_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_floating_ip_info': result['hcloud_floating_ip_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,208 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_image_info
short_description: Gather infos about your Hetzner Cloud images.
version_added: "2.8"
description:
- Gather infos about your Hetzner Cloud images.
- This module was called C(hcloud_location_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_location_facts).
Note that the M(hcloud_image_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_image_info)!
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the image you want to get.
type: int
name:
description:
- The name of the image you want to get.
type: str
label_selector:
description:
- The label selector for the images you want to get.
type: str
type:
description:
- The label selector for the images you want to get.
default: system
choices: [ system, snapshot, backup ]
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud image infos
hcloud_image_info:
register: output
- name: Print the gathered infos
debug:
var: output
"""
RETURN = """
hcloud_image_info:
description: The image infos as list
returned: always
type: complex
contains:
id:
description: Numeric identifier of the image
returned: always
type: int
sample: 1937415
type:
description: Type of the image
returned: always
type: str
sample: system
status:
description: Status of the image
returned: always
type: str
sample: available
name:
description: Name of the image
returned: always
type: str
sample: ubuntu-18.04
description:
description: Detail description of the image
returned: always
type: str
sample: Ubuntu 18.04 Standard 64 bit
os_flavor:
description: OS flavor of the image
returned: always
type: str
sample: ubuntu
os_version:
description: OS version of the image
returned: always
type: str
sample: 18.04
labels:
description: User-defined labels (key-value pairs)
returned: always
type: dict
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudImageInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_image_info")
self.hcloud_image_info = None
def _prepare_result(self):
tmp = []
for image in self.hcloud_image_info:
if image is not None:
tmp.append({
"id": to_native(image.id),
"status": to_native(image.status),
"type": to_native(image.type),
"name": to_native(image.name),
"description": to_native(image.description),
"os_flavor": to_native(image.os_flavor),
"os_version": to_native(image.os_version),
"labels": image.labels,
})
return tmp
def get_images(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_image_info = [self.client.images.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_image_info = [self.client.images.get_by_name(
self.module.params.get("name")
)]
else:
params = {}
label_selector = self.module.params.get("label_selector")
if label_selector:
params["label_selector"] = label_selector
image_type = self.module.params.get("type")
if image_type:
params["type"] = image_type
self.hcloud_image_info = self.client.images.get_all(**params)
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
label_selector={"type": "str"},
type={"choices": ["system", "snapshot", "backup"], "default": "system", "type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudImageInfo.define_module()
is_old_facts = module._name == 'hcloud_image_facts'
if is_old_facts:
module.deprecate("The 'hcloud_image_facts' module has been renamed to 'hcloud_image_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudImageInfo(module)
hcloud.get_images()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_imagen_facts': result['hcloud_image_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_image_info': result['hcloud_image_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,169 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_location_info
short_description: Gather infos about your Hetzner Cloud locations.
version_added: "2.8"
description:
- Gather infos about your Hetzner Cloud locations.
- This module was called C(hcloud_location_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_location_facts).
Note that the M(hcloud_location_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_location_info)!
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the location you want to get.
type: int
name:
description:
- The name of the location you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud location infos
hcloud_location_info:
register: output
- name: Print the gathered infos
debug:
var: output
"""
RETURN = """
hcloud_location_info:
description: The location infos as list
returned: always
type: complex
contains:
id:
description: Numeric identifier of the location
returned: always
type: int
sample: 1937415
name:
description: Name of the location
returned: always
type: str
sample: fsn1
description:
description: Detail description of the location
returned: always
type: str
sample: Falkenstein DC Park 1
country:
description: Country code of the location
returned: always
type: str
sample: DE
city:
description: City of the location
returned: always
type: str
sample: Falkenstein
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudLocationInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_location_info")
self.hcloud_location_info = None
def _prepare_result(self):
tmp = []
for location in self.hcloud_location_info:
if location is not None:
tmp.append({
"id": to_native(location.id),
"name": to_native(location.name),
"description": to_native(location.description),
"city": to_native(location.city),
"country": to_native(location.country)
})
return tmp
def get_locations(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_location_info = [self.client.locations.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_location_info = [self.client.locations.get_by_name(
self.module.params.get("name")
)]
else:
self.hcloud_location_info = self.client.locations.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudLocationInfo.define_module()
is_old_facts = module._name == 'hcloud_location_facts'
if is_old_facts:
module.deprecate("The 'hcloud_location_info' module has been renamed to 'hcloud_location_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudLocationInfo(module)
hcloud.get_locations()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_location_facts': result['hcloud_location_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_location_info': result['hcloud_location_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,248 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_network
short_description: Create and manage cloud Networks on the Hetzner Cloud.
version_added: "2.9"
description:
- Create, update and manage cloud Networks on the Hetzner Cloud.
- You need at least hcloud-python 1.3.0.
author:
- Lukas Kaemmerling (@lkaemmerling)
options:
id:
description:
- The ID of the Hetzner Cloud Networks to manage.
- Only required if no Network I(name) is given.
type: int
name:
description:
- The Name of the Hetzner Cloud Network to manage.
- Only required if no Network I(id) is given or a Network does not exists.
type: str
ip_range:
description:
- IP range of the Network.
- Required if Network does not exists.
type: str
labels:
description:
- User-defined labels (key-value pairs).
type: dict
delete_protection:
description:
- Protect the Network for deletion.
type: bool
version_added: "2.10"
state:
description:
- State of the Network.
default: present
choices: [ absent, present ]
type: str
requirements:
- hcloud-python >= 1.3.0
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a basic network
hcloud_network:
name: my-network
ip_range: 10.0.0.0/8
state: present
- name: Ensure the Network is absent (remove if needed)
hcloud_network:
name: my-network
state: absent
"""
RETURN = """
hcloud_network:
description: The Network
returned: always
type: complex
contains:
id:
description: ID of the Network
type: int
returned: always
sample: 12345
name:
description: Name of the Network
type: str
returned: always
sample: my-volume
ip_range:
description: IP range of the Network
type: str
returned: always
sample: 10.0.0.0/8
delete_protection:
description: True if Network is protected for deletion
type: bool
returned: always
sample: false
version_added: "2.10"
labels:
description: User-defined labels (key-value pairs)
type: dict
returned: always
sample:
key: value
mylabel: 123
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
APIException = None
class AnsibleHcloudNetwork(Hcloud):
def __init__(self, module):
super(AnsibleHcloudNetwork, self).__init__(module, "hcloud_network")
self.hcloud_network = None
def _prepare_result(self):
return {
"id": to_native(self.hcloud_network.id),
"name": to_native(self.hcloud_network.name),
"ip_range": to_native(self.hcloud_network.ip_range),
"delete_protection": self.hcloud_network.protection["delete"],
"labels": self.hcloud_network.labels,
}
def _get_network(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_network = self.client.networks.get_by_id(
self.module.params.get("id")
)
else:
self.hcloud_network = self.client.networks.get_by_name(
self.module.params.get("name")
)
except APIException as e:
self.module.fail_json(msg=e.message)
def _create_network(self):
self.module.fail_on_missing_params(
required_params=["name", "ip_range"]
)
params = {
"name": self.module.params.get("name"),
"ip_range": self.module.params.get("ip_range"),
"labels": self.module.params.get("labels"),
}
if not self.module.check_mode:
self.client.networks.create(**params)
self._mark_as_changed()
self._get_network()
def _update_network(self):
try:
labels = self.module.params.get("labels")
if labels is not None and labels != self.hcloud_network.labels:
if not self.module.check_mode:
self.hcloud_network.update(labels=labels)
self._mark_as_changed()
ip_range = self.module.params.get("ip_range")
if ip_range is not None and ip_range != self.hcloud_network.ip_range:
if not self.module.check_mode:
self.hcloud_network.change_ip_range(ip_range=ip_range).wait_until_finished()
self._mark_as_changed()
delete_protection = self.module.params.get("delete_protection")
if delete_protection is not None and delete_protection != self.hcloud_network.protection["delete"]:
if not self.module.check_mode:
self.hcloud_network.change_protection(delete=delete_protection).wait_until_finished()
self._mark_as_changed()
except APIException as e:
self.module.fail_json(msg=e.message)
self._get_network()
def present_network(self):
self._get_network()
if self.hcloud_network is None:
self._create_network()
else:
self._update_network()
def delete_network(self):
try:
self._get_network()
if self.hcloud_network is not None:
if not self.module.check_mode:
self.client.networks.delete(self.hcloud_network)
self._mark_as_changed()
except APIException as e:
self.module.fail_json(msg=e.message)
self.hcloud_network = None
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
ip_range={"type": "str"},
labels={"type": "dict"},
delete_protection={"type": "bool"},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
required_one_of=[['id', 'name']],
supports_check_mode=True,
)
def main():
module = AnsibleHcloudNetwork.define_module()
hcloud = AnsibleHcloudNetwork(module)
state = module.params["state"]
if state == "absent":
hcloud.delete_network()
elif state == "present":
hcloud.present_network()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,213 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_network_info
short_description: Gather info about your Hetzner Cloud networks.
version_added: "2.9"
description:
- Gather info about your Hetzner Cloud networks.
author:
- Christopher Schmitt (@cschmitt-hcloud)
options:
id:
description:
- The ID of the network you want to get.
type: int
name:
description:
- The name of the network you want to get.
type: str
label_selector:
description:
- The label selector for the network you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud network info
local_action:
module: hcloud_network_info
- name: Print the gathered info
debug:
var: hcloud_network_info
"""
RETURN = """
hcloud_network_info:
description: The network info as list
returned: always
type: complex
contains:
id:
description: Numeric identifier of the network
returned: always
type: int
sample: 1937415
name:
description: Name of the network
returned: always
type: str
sample: awesome-network
ip_range:
description: IP range of the network
returned: always
type: str
sample: 10.0.0.0/16
subnetworks:
description: Subnetworks belonging to the network
returned: always
type: complex
routes:
description: Routes belonging to the network
returned: always
type: complex
servers:
description: Servers attached to the network
returned: always
type: complex
delete_protection:
description: True if the network is protected for deletion
returned: always
type: bool
version_added: "2.10"
labels:
description: Labels of the network
returned: always
type: dict
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudNetworkInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_network_info")
self.hcloud_network_info = None
def _prepare_result(self):
tmp = []
for network in self.hcloud_network_info:
if network is not None:
subnets = []
for subnet in network.subnets:
prepared_subnet = {
"type": subnet.type,
"ip_range": subnet.ip_range,
"network_zone": subnet.network_zone,
"gateway": subnet.gateway,
}
subnets.append(prepared_subnet)
routes = []
for route in network.routes:
prepared_route = {
"destination": route.destination,
"gateway": route.gateway
}
routes.append(prepared_route)
servers = []
for server in network.servers:
prepared_server = {
"id": to_native(server.id),
"name": to_native(server.name),
"ipv4_address": to_native(server.public_net.ipv4.ip),
"ipv6": to_native(server.public_net.ipv6.ip),
"image": to_native(server.image.name),
"server_type": to_native(server.server_type.name),
"datacenter": to_native(server.datacenter.name),
"location": to_native(server.datacenter.location.name),
"rescue_enabled": server.rescue_enabled,
"backup_window": to_native(server.backup_window),
"labels": server.labels,
"status": to_native(server.status),
}
servers.append(prepared_server)
tmp.append({
"id": to_native(network.id),
"name": to_native(network.name),
"ip_range": to_native(network.ip_range),
"subnetworks": subnets,
"routes": routes,
"servers": servers,
"labels": network.labels,
"delete_protection": network.protection["delete"],
})
return tmp
def get_networks(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_network_info = [self.client.networks.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_network_info = [self.client.networks.get_by_name(
self.module.params.get("name")
)]
elif self.module.params.get("label_selector") is not None:
self.hcloud_network_info = self.client.networks.get_all(
label_selector=self.module.params.get("label_selector"))
else:
self.hcloud_network_info = self.client.networks.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
label_selector={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudNetworkInfo.define_module()
hcloud = AnsibleHcloudNetworkInfo(module)
hcloud.get_networks()
result = hcloud.get_result()
info = {
'hcloud_network_info': result['hcloud_network_info']
}
module.exit_json(**info)
if __name__ == "__main__":
main()

@ -1,230 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_rdns
short_description: Create and manage reverse DNS entries on the Hetzner Cloud.
version_added: "2.9"
description:
- Create, update and delete reverse DNS entries on the Hetzner Cloud.
author:
- Lukas Kaemmerling (@lkaemmerling)
options:
server:
description:
- The name of the Hetzner Cloud server you want to add the reverse DNS entry to.
type: str
required: true
ip_address:
description:
- The IP address that should point to I(dns_ptr).
type: str
required: true
dns_ptr:
description:
- The DNS address the I(ip_address) should resolve to.
- Omit the param to reset the reverse DNS entry to the default value.
type: str
state:
description:
- State of the reverse DNS entry.
default: present
choices: [ absent, present ]
type: str
requirements:
- hcloud-python >= 1.3.0
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a reverse DNS entry for a server
hcloud_rdns:
server: my-server
ip_address: 123.123.123.123
dns_ptr: example.com
state: present
- name: Ensure the reverse DNS entry is absent (remove if needed)
hcloud_rdns:
server: my-server
ip_address: 123.123.123.123
dns_ptr: example.com
state: absent
"""
RETURN = """
hcloud_rdns:
description: The reverse DNS entry
returned: always
type: complex
contains:
server:
description: Name of the server
type: str
returned: always
sample: my-server
ip_address:
description: The IP address that point to the DNS ptr
type: str
returned: always
sample: 123.123.123.123
dns_ptr:
description: The DNS that resolves to the IP
type: str
returned: always
sample: example.com
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
from ansible.module_utils.network.common import utils
try:
from hcloud import APIException
except ImportError:
APIException = None
class AnsibleHcloudReverseDNS(Hcloud):
def __init__(self, module):
super(AnsibleHcloudReverseDNS, self).__init__(module, "hcloud_rdns")
self.hcloud_server = None
self.hcloud_rdns = None
def _prepare_result(self):
return {
"server": to_native(self.hcloud_server.name),
"ip_address": to_native(self.hcloud_rdns["ip_address"]),
"dns_ptr": to_native(self.hcloud_rdns["dns_ptr"]),
}
def _get_server(self):
try:
self.hcloud_server = self.client.servers.get_by_name(
self.module.params.get("server")
)
except APIException as e:
self.module.fail_json(msg=e.message)
def _get_rdns(self):
ip_address = self.module.params.get("ip_address")
if utils.validate_ip_address(ip_address):
if self.hcloud_server.public_net.ipv4.ip == ip_address:
self.hcloud_rdns = {
"ip_address": self.hcloud_server.public_net.ipv4.ip,
"dns_ptr": self.hcloud_server.public_net.ipv4.dns_ptr,
}
else:
self.module.fail_json(msg="The selected server does not have this IP address")
elif utils.validate_ip_v6_address(ip_address):
for ipv6_address_dns_ptr in self.hcloud_server.public_net.ipv6.dns_ptr:
if ipv6_address_dns_ptr["ip"] == ip_address:
self.hcloud_rdns = {
"ip_address": ipv6_address_dns_ptr["ip"],
"dns_ptr": ipv6_address_dns_ptr["dns_ptr"],
}
else:
self.module.fail_json(msg="The given IP address is not valid")
def _create_rdns(self):
self.module.fail_on_missing_params(
required_params=["dns_ptr"]
)
params = {
"ip": self.module.params.get("ip_address"),
"dns_ptr": self.module.params.get("dns_ptr"),
}
if not self.module.check_mode:
self.hcloud_server.change_dns_ptr(**params).wait_until_finished()
self._mark_as_changed()
self._get_server()
self._get_rdns()
def _update_rdns(self):
dns_ptr = self.module.params.get("dns_ptr")
if dns_ptr != self.hcloud_rdns["dns_ptr"]:
params = {
"ip": self.module.params.get("ip_address"),
"dns_ptr": dns_ptr,
}
if not self.module.check_mode:
self.hcloud_server.change_dns_ptr(**params).wait_until_finished()
self._mark_as_changed()
self._get_server()
self._get_rdns()
def present_rdns(self):
self._get_server()
self._get_rdns()
if self.hcloud_rdns is None:
self._create_rdns()
else:
self._update_rdns()
def delete_rdns(self):
self._get_server()
self._get_rdns()
if self.hcloud_rdns is not None:
if not self.module.check_mode:
self.hcloud_server.change_dns_ptr(ip=self.hcloud_rdns['ip_address'], dns_ptr=None)
self._mark_as_changed()
self.hcloud_rdns = None
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
server={"type": "str", "required": True},
ip_address={"type": "str", "required": True},
dns_ptr={"type": "str"},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudReverseDNS.define_module()
hcloud = AnsibleHcloudReverseDNS(module)
state = module.params["state"]
if state == "absent":
hcloud.delete_rdns()
elif state == "present":
hcloud.present_rdns()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,200 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_route
short_description: Create and delete cloud routes on the Hetzner Cloud.
version_added: "2.9"
description:
- Create, update and delete cloud routes on the Hetzner Cloud.
author:
- Lukas Kaemmerling (@lkaemmerling)
options:
network:
description:
- The name of the Hetzner Cloud Network.
type: str
required: true
destination:
description:
- Destination network or host of this route.
type: str
required: true
gateway:
description:
- Gateway for the route.
type: str
required: true
state:
description:
- State of the route.
default: present
choices: [ absent, present ]
type: str
requirements:
- hcloud-python >= 1.3.0
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a basic route
hcloud_route:
network: my-network
destination: 10.100.1.0/24
gateway: 10.0.1.1
state: present
- name: Ensure the route is absent
hcloud_route:
network: my-network
destination: 10.100.1.0/24
gateway: 10.0.1.1
state: absent
"""
RETURN = """
hcloud_route:
description: One Route of a Network
returned: always
type: complex
contains:
network:
description: Name of the Network
type: str
returned: always
sample: my-network
destination:
description: Destination network or host of this route
type: str
returned: always
sample: 10.0.0.0/8
gateway:
description: Gateway of the route
type: str
returned: always
sample: 10.0.0.1
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
from hcloud.networks.domain import NetworkRoute
except ImportError:
APIException = None
NetworkSubnet = None
class AnsibleHcloudRoute(Hcloud):
def __init__(self, module):
super(AnsibleHcloudRoute, self).__init__(module, "hcloud_route")
self.hcloud_network = None
self.hcloud_route = None
def _prepare_result(self):
return {
"network": to_native(self.hcloud_network.name),
"destination": to_native(self.hcloud_route.destination),
"gateway": self.hcloud_route.gateway,
}
def _get_network(self):
try:
self.hcloud_network = self.client.networks.get_by_name(self.module.params.get("network"))
self.hcloud_route = None
except APIException as e:
self.module.fail_json(msg=e.message)
def _get_route(self):
destination = self.module.params.get("destination")
gateway = self.module.params.get("gateway")
for route in self.hcloud_network.routes:
if route.destination == destination and route.gateway == gateway:
self.hcloud_route = route
def _create_route(self):
route = NetworkRoute(
destination=self.module.params.get("destination"),
gateway=self.module.params.get('gateway')
)
if not self.module.check_mode:
try:
self.hcloud_network.add_route(route=route).wait_until_finished()
except APIException as e:
self.module.fail_json(msg=e.message)
self._mark_as_changed()
self._get_network()
self._get_route()
def present_route(self):
self._get_network()
self._get_route()
if self.hcloud_route is None:
self._create_route()
def delete_route(self):
self._get_network()
self._get_route()
if self.hcloud_route is not None and self.hcloud_network is not None:
if not self.module.check_mode:
self.hcloud_network.delete_route(self.hcloud_route).wait_until_finished()
self._mark_as_changed()
self.hcloud_route = None
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
network={"type": "str", "required": True},
destination={"type": "str", "required": True},
gateway={"type": "str", "required": True},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudRoute.define_module()
hcloud = AnsibleHcloudRoute(module)
state = module.params["state"]
if state == "absent":
hcloud.delete_route()
elif state == "present":
hcloud.present_route()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,555 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_server
short_description: Create and manage cloud servers on the Hetzner Cloud.
version_added: "2.8"
description:
- Create, update and manage cloud servers on the Hetzner Cloud.
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the Hetzner Cloud server to manage.
- Only required if no server I(name) is given
type: int
name:
description:
- The Name of the Hetzner Cloud server to manage.
- Only required if no server I(id) is given or a server does not exists.
type: str
server_type:
description:
- The Server Type of the Hetzner Cloud server to manage.
- Required if server does not exists.
type: str
ssh_keys:
description:
- List of SSH key names
- The key names correspond to the SSH keys configured for your
Hetzner Cloud account access.
type: list
volumes:
description:
- List of Volumes IDs that should be attached to the server on server creation.
type: list
image:
description:
- Image the server should be created from.
- Required if server does not exists.
type: str
location:
description:
- Location of Server.
- Required if no I(datacenter) is given and server does not exists.
type: str
datacenter:
description:
- Datacenter of Server.
- Required of no I(location) is given and server does not exists.
type: str
backups:
description:
- Enable or disable Backups for the given Server.
type: bool
default: no
upgrade_disk:
description:
- Resize the disk size, when resizing a server.
- If you want to downgrade the server later, this value should be False.
type: bool
default: no
force_upgrade:
description:
- Force the upgrade of the server.
- Power off the server if it is running on upgrade.
type: bool
default: no
user_data:
description:
- User Data to be passed to the server on creation.
- Only used if server does not exists.
type: str
rescue_mode:
description:
- Add the Hetzner rescue system type you want the server to be booted into.
type: str
version_added: 2.9
labels:
description:
- User-defined labels (key-value pairs).
type: dict
delete_protection:
description:
- Protect the Server for deletion.
- Needs to be the same as I(rebuild_protection).
type: bool
version_added: "2.10"
rebuild_protection:
description:
- Protect the Server for rebuild.
- Needs to be the same as I(delete_protection).
type: bool
version_added: "2.10"
state:
description:
- State of the server.
default: present
choices: [ absent, present, restarted, started, stopped, rebuild ]
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a basic server
hcloud_server:
name: my-server
server_type: cx11
image: ubuntu-18.04
state: present
- name: Create a basic server with ssh key
hcloud_server:
name: my-server
server_type: cx11
image: ubuntu-18.04
location: fsn1
ssh_keys:
- me@myorganisation
state: present
- name: Resize an existing server
hcloud_server:
name: my-server
server_type: cx21
upgrade_disk: yes
state: present
- name: Ensure the server is absent (remove if needed)
hcloud_server:
name: my-server
state: absent
- name: Ensure the server is started
hcloud_server:
name: my-server
state: started
- name: Ensure the server is stopped
hcloud_server:
name: my-server
state: stopped
- name: Ensure the server is restarted
hcloud_server:
name: my-server
state: restarted
- name: Ensure the server is will be booted in rescue mode and therefore restarted
hcloud_server:
name: my-server
rescue_mode: linux64
state: restarted
- name: Ensure the server is rebuild
hcloud_server:
name: my-server
image: ubuntu-18.04
state: rebuild
"""
RETURN = """
hcloud_server:
description: The server instance
returned: Always
type: complex
contains:
id:
description: Numeric identifier of the server
returned: always
type: int
sample: 1937415
name:
description: Name of the server
returned: always
type: str
sample: my-server
status:
description: Status of the server
returned: always
type: str
sample: running
server_type:
description: Name of the server type of the server
returned: always
type: str
sample: cx11
ipv4_address:
description: Public IPv4 address of the server
returned: always
type: str
sample: 116.203.104.109
ipv6:
description: IPv6 network of the server
returned: always
type: str
sample: 2a01:4f8:1c1c:c140::/64
location:
description: Name of the location of the server
returned: always
type: str
sample: fsn1
datacenter:
description: Name of the datacenter of the server
returned: always
type: str
sample: fsn1-dc14
rescue_enabled:
description: True if rescue mode is enabled, Server will then boot into rescue system on next reboot
returned: always
type: bool
sample: false
backup_window:
description: Time window (UTC) in which the backup will run, or null if the backups are not enabled
returned: always
type: bool
sample: 22-02
labels:
description: User-defined labels (key-value pairs)
returned: always
type: dict
delete_protection:
description: True if server is protected for deletion
type: bool
returned: always
sample: false
version_added: "2.10"
rebuild_protection:
description: True if server is protected for rebuild
type: bool
returned: always
sample: false
version_added: "2.10"
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud.volumes.domain import Volume
from hcloud.ssh_keys.domain import SSHKey
from hcloud.servers.domain import Server
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudServer(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_server")
self.hcloud_server = None
def _prepare_result(self):
image = None if self.hcloud_server.image is None else to_native(self.hcloud_server.image.name)
return {
"id": to_native(self.hcloud_server.id),
"name": to_native(self.hcloud_server.name),
"ipv4_address": to_native(self.hcloud_server.public_net.ipv4.ip),
"ipv6": to_native(self.hcloud_server.public_net.ipv6.ip),
"image": image,
"server_type": to_native(self.hcloud_server.server_type.name),
"datacenter": to_native(self.hcloud_server.datacenter.name),
"location": to_native(self.hcloud_server.datacenter.location.name),
"rescue_enabled": self.hcloud_server.rescue_enabled,
"backup_window": to_native(self.hcloud_server.backup_window),
"labels": self.hcloud_server.labels,
"delete_protection": self.hcloud_server.protection["delete"],
"rebuild_protection": self.hcloud_server.protection["rebuild"],
"status": to_native(self.hcloud_server.status),
}
def _get_server(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_server = self.client.servers.get_by_id(
self.module.params.get("id")
)
else:
self.hcloud_server = self.client.servers.get_by_name(
self.module.params.get("name")
)
except APIException as e:
self.module.fail_json(msg=e.message)
def _create_server(self):
self.module.fail_on_missing_params(
required_params=["name", "server_type", "image"]
)
params = {
"name": self.module.params.get("name"),
"server_type": self.client.server_types.get_by_name(
self.module.params.get("server_type")
),
"user_data": self.module.params.get("user_data"),
"labels": self.module.params.get("labels"),
}
if self.client.images.get_by_name(self.module.params.get("image")) is not None:
# When image name is not available look for id instead
params["image"] = self.client.images.get_by_name(self.module.params.get("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"] = [
SSHKey(name=ssh_key_name)
for ssh_key_name in self.module.params.get("ssh_keys")
]
if self.module.params.get("volumes") is not None:
params["volumes"] = [
Volume(id=volume_id) for volume_id in self.module.params.get("volumes")
]
if self.module.params.get("location") is None and self.module.params.get("datacenter") is None:
# When not given, the API will choose the location.
params["location"] = None
params["datacenter"] = None
elif self.module.params.get("location") is not None and self.module.params.get("datacenter") is None:
params["location"] = self.client.locations.get_by_name(
self.module.params.get("location")
)
elif self.module.params.get("location") is None and self.module.params.get("datacenter") is not None:
params["datacenter"] = self.client.datacenters.get_by_name(
self.module.params.get("datacenter")
)
if not self.module.check_mode:
resp = self.client.servers.create(**params)
self.result["root_password"] = resp.root_password
resp.action.wait_until_finished(max_retries=1000)
[action.wait_until_finished() for action in resp.next_actions]
rescue_mode = self.module.params.get("rescue_mode")
if rescue_mode:
self._get_server()
self._set_rescue_mode(rescue_mode)
self._mark_as_changed()
self._get_server()
def _update_server(self):
try:
rescue_mode = self.module.params.get("rescue_mode")
if rescue_mode and self.hcloud_server.rescue_enabled is False:
if not self.module.check_mode:
self._set_rescue_mode(rescue_mode)
self._mark_as_changed()
elif not rescue_mode and self.hcloud_server.rescue_enabled is True:
if not self.module.check_mode:
self.hcloud_server.disable_rescue().wait_until_finished()
self._mark_as_changed()
if self.module.params.get("backups") and self.hcloud_server.backup_window is None:
if not self.module.check_mode:
self.hcloud_server.enable_backup().wait_until_finished()
self._mark_as_changed()
elif not self.module.params.get("backups") and self.hcloud_server.backup_window is not None:
if not self.module.check_mode:
self.hcloud_server.disable_backup().wait_until_finished()
self._mark_as_changed()
labels = self.module.params.get("labels")
if labels is not None and labels != self.hcloud_server.labels:
if not self.module.check_mode:
self.hcloud_server.update(labels=labels)
self._mark_as_changed()
server_type = self.module.params.get("server_type")
if server_type is not None and self.hcloud_server.server_type.name != server_type:
previous_server_status = self.hcloud_server.status
state = self.module.params.get("state")
if previous_server_status == Server.STATUS_RUNNING:
if not self.module.check_mode:
if self.module.params.get("force_upgrade") or state == "stopped":
self.stop_server() # Only stopped server can be upgraded
else:
self.module.warn(
"You can not upgrade a running instance %s. You need to stop the instance or use force_upgrade=yes."
% self.hcloud_server.name
)
timeout = 100
if self.module.params.get("upgrade_disk"):
timeout = (
1000
) # When we upgrade the disk too the resize progress takes some more time.
if not self.module.check_mode:
self.hcloud_server.change_type(
server_type=self.client.server_types.get_by_name(server_type),
upgrade_disk=self.module.params.get("upgrade_disk"),
).wait_until_finished(timeout)
if state == "present" and previous_server_status == Server.STATUS_RUNNING or state == "started":
self.start_server()
self._mark_as_changed()
delete_protection = self.module.params.get("delete_protection")
rebuild_protection = self.module.params.get("rebuild_protection")
if (delete_protection is not None and rebuild_protection is not None) and (
delete_protection != self.hcloud_server.protection["delete"] or rebuild_protection !=
self.hcloud_server.protection["rebuild"]):
if not self.module.check_mode:
self.hcloud_server.change_protection(delete=delete_protection,
rebuild=rebuild_protection).wait_until_finished()
self._mark_as_changed()
self._get_server()
except APIException as e:
self.module.fail_json(msg=e.message)
def _set_rescue_mode(self, rescue_mode):
if self.module.params.get("ssh_keys"):
resp = self.hcloud_server.enable_rescue(type=rescue_mode,
ssh_keys=[self.client.ssh_keys.get_by_name(ssh_key_name).id
for
ssh_key_name in
self.module.params.get("ssh_keys")])
else:
resp = self.hcloud_server.enable_rescue(type=rescue_mode)
resp.action.wait_until_finished()
self.result["root_password"] = resp.root_password
def start_server(self):
try:
if self.hcloud_server.status != Server.STATUS_RUNNING:
if not self.module.check_mode:
self.client.servers.power_on(self.hcloud_server).wait_until_finished()
self._mark_as_changed()
self._get_server()
except APIException as e:
self.module.fail_json(msg=e.message)
def stop_server(self):
try:
if self.hcloud_server.status != Server.STATUS_OFF:
if not self.module.check_mode:
self.client.servers.power_off(self.hcloud_server).wait_until_finished()
self._mark_as_changed()
self._get_server()
except APIException as e:
self.module.fail_json(msg=e.message)
def rebuild_server(self):
self.module.fail_on_missing_params(
required_params=["image"]
)
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()
self._mark_as_changed()
self._get_server()
except APIException as e:
self.module.fail_json(msg=e.message)
def present_server(self):
self._get_server()
if self.hcloud_server is None:
self._create_server()
else:
self._update_server()
def delete_server(self):
try:
self._get_server()
if self.hcloud_server is not None:
if not self.module.check_mode:
self.client.servers.delete(self.hcloud_server).wait_until_finished()
self._mark_as_changed()
self.hcloud_server = None
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
image={"type": "str"},
server_type={"type": "str"},
location={"type": "str"},
datacenter={"type": "str"},
user_data={"type": "str"},
ssh_keys={"type": "list"},
volumes={"type": "list"},
labels={"type": "dict"},
backups={"type": "bool", "default": False},
upgrade_disk={"type": "bool", "default": False},
force_upgrade={"type": "bool", "default": False},
rescue_mode={"type": "str"},
delete_protection={"type": "bool"},
rebuild_protection={"type": "bool"},
state={
"choices": ["absent", "present", "restarted", "started", "stopped", "rebuild"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
required_one_of=[['id', 'name']],
mutually_exclusive=[["location", "datacenter"]],
required_together=[["delete_protection", "rebuild_protection"]],
supports_check_mode=True,
)
def main():
module = AnsibleHcloudServer.define_module()
hcloud = AnsibleHcloudServer(module)
state = module.params.get("state")
if state == "absent":
hcloud.delete_server()
elif state == "present":
hcloud.present_server()
elif state == "started":
hcloud.present_server()
hcloud.start_server()
elif state == "stopped":
hcloud.present_server()
hcloud.stop_server()
elif state == "restarted":
hcloud.present_server()
hcloud.stop_server()
hcloud.start_server()
elif state == "rebuild":
hcloud.present_server()
hcloud.rebuild_server()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,229 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_server_info
short_description: Gather infos about your Hetzner Cloud servers.
version_added: "2.8"
description:
- Gather infos about your Hetzner Cloud servers.
- This module was called C(hcloud_server_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_server_facts).
Note that the M(hcloud_server_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_server_info)!
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the server you want to get.
type: int
name:
description:
- The name of the server you want to get.
type: str
label_selector:
description:
- The label selector for the server you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud server infos
hcloud_server_info:
register: output
- name: Print the gathered infos
debug:
var: output.hcloud_server_info
"""
RETURN = """
hcloud_server_info:
description: The server infos as list
returned: always
type: complex
contains:
id:
description: Numeric identifier of the server
returned: always
type: int
sample: 1937415
name:
description: Name of the server
returned: always
type: str
sample: my-server
status:
description: Status of the server
returned: always
type: str
sample: running
server_type:
description: Name of the server type of the server
returned: always
type: str
sample: cx11
ipv4_address:
description: Public IPv4 address of the server
returned: always
type: str
sample: 116.203.104.109
ipv6:
description: IPv6 network of the server
returned: always
type: str
sample: 2a01:4f8:1c1c:c140::/64
location:
description: Name of the location of the server
returned: always
type: str
sample: fsn1
datacenter:
description: Name of the datacenter of the server
returned: always
type: str
sample: fsn1-dc14
rescue_enabled:
description: True if rescue mode is enabled, Server will then boot into rescue system on next reboot
returned: always
type: bool
sample: false
backup_window:
description: Time window (UTC) in which the backup will run, or null if the backups are not enabled
returned: always
type: bool
sample: 22-02
labels:
description: User-defined labels (key-value pairs)
returned: always
type: dict
delete_protection:
description: True if server is protected for deletion
type: bool
returned: always
sample: false
version_added: "2.10"
rebuild_protection:
description: True if server is protected for rebuild
type: bool
returned: always
sample: false
version_added: "2.10"
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudServerInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_server_info")
self.hcloud_server_info = None
def _prepare_result(self):
tmp = []
for server in self.hcloud_server_info:
if server is not None:
image = None if server.image is None else to_native(server.image.name)
tmp.append({
"id": to_native(server.id),
"name": to_native(server.name),
"ipv4_address": to_native(server.public_net.ipv4.ip),
"ipv6": to_native(server.public_net.ipv6.ip),
"image": image,
"server_type": to_native(server.server_type.name),
"datacenter": to_native(server.datacenter.name),
"location": to_native(server.datacenter.location.name),
"rescue_enabled": server.rescue_enabled,
"backup_window": to_native(server.backup_window),
"labels": server.labels,
"status": to_native(server.status),
"delete_protection": server.protection["delete"],
"rebuild_protection": server.protection["rebuild"],
})
return tmp
def get_servers(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_server_info = [self.client.servers.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_server_info = [self.client.servers.get_by_name(
self.module.params.get("name")
)]
elif self.module.params.get("label_selector") is not None:
self.hcloud_server_info = self.client.servers.get_all(
label_selector=self.module.params.get("label_selector"))
else:
self.hcloud_server_info = self.client.servers.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
label_selector={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudServerInfo.define_module()
is_old_facts = module._name == 'hcloud_server_facts'
if is_old_facts:
module.deprecate("The 'hcloud_server_facts' module has been renamed to 'hcloud_server_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudServerInfo(module)
hcloud.get_servers()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_server_facts': result['hcloud_server_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_server_info': result['hcloud_server_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,229 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_server_network
short_description: Manage the relationship between Hetzner Cloud Networks and servers
version_added: "2.9"
description:
- Create and delete the relationship Hetzner Cloud Networks and servers
author:
- Lukas Kaemmerling (@lkaemmerling)
options:
network:
description:
- The name of the Hetzner Cloud Networks.
type: str
required: true
server:
description:
- The name of the Hetzner Cloud server.
type: str
required: true
ip:
description:
- The IP the server should have.
type: str
alias_ips:
description:
- Alias IPs the server has.
type: list
state:
description:
- State of the server_network.
default: present
choices: [ absent, present ]
type: str
requirements:
- hcloud-python >= 1.3.0
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a basic server network
hcloud_server_network:
network: my-network
server: my-server
state: present
- name: Create a server network and specify the ip address
hcloud_server_network:
network: my-network
server: my-server
ip: 10.0.0.1
state: present
- name: Create a server network and add alias ips
hcloud_server_network:
network: my-network
server: my-server
ip: 10.0.0.1
alias_ips:
- 10.1.0.1
- 10.2.0.1
state: present
- name: Ensure the server network is absent (remove if needed)
hcloud_server_network:
network: my-network
server: my-server
state: absent
"""
RETURN = """
hcloud_server_network:
description: The relationship between a server and a network
returned: always
type: complex
contains:
network:
description: Name of the Network
type: str
returned: always
sample: my-network
server:
description: Name of the server
type: str
returned: always
sample: my-server
ip:
description: IP of the server within the Network ip range
type: str
returned: always
sample: 10.0.0.8
alias_ips:
description: Alias IPs of the server within the Network ip range
type: str
returned: always
sample: [10.1.0.1, ...]
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
APIException = None
NetworkSubnet = None
class AnsibleHcloudServerNetwork(Hcloud):
def __init__(self, module):
super(AnsibleHcloudServerNetwork, self).__init__(module, "hcloud_server_network")
self.hcloud_network = None
self.hcloud_server = None
self.hcloud_server_network = None
def _prepare_result(self):
return {
"network": to_native(self.hcloud_network.name),
"server": to_native(self.hcloud_server.name),
"ip": to_native(self.hcloud_server_network.ip),
"alias_ips": self.hcloud_server_network.alias_ips,
}
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_server_network = None
except APIException as e:
self.module.fail_json(msg=e.message)
def _get_server_network(self):
for privateNet in self.hcloud_server.private_net:
if privateNet.network.id == self.hcloud_network.id:
self.hcloud_server_network = privateNet
def _create_server_network(self):
params = {
"network": self.hcloud_network
}
if self.module.params.get("ip") is not None:
params["ip"] = self.module.params.get("ip")
if self.module.params.get("alias_ips") is not None:
params["alias_ips"] = self.module.params.get("alias_ips")
if not self.module.check_mode:
try:
self.hcloud_server.attach_to_network(**params).wait_until_finished()
except APIException as e:
self.module.fail_json(msg=e.message)
self._mark_as_changed()
self._get_server_and_network()
self._get_server_network()
def present_server_network(self):
self._get_server_and_network()
self._get_server_network()
if self.hcloud_server_network is None:
self._create_server_network()
def delete_server_network(self):
self._get_server_and_network()
self._get_server_network()
if self.hcloud_server_network is not None and self.hcloud_server is not None:
if not self.module.check_mode:
self.hcloud_server.detach_from_network(self.hcloud_server_network.network).wait_until_finished()
self._mark_as_changed()
self.hcloud_server_network = None
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
network={"type": "str", "required": True},
server={"type": "str", "required": True},
ip={"type": "str"},
alias_ips={"type": "list"},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudServerNetwork.define_module()
hcloud = AnsibleHcloudServerNetwork(module)
state = module.params["state"]
if state == "absent":
hcloud.delete_server_network()
elif state == "present":
hcloud.present_server_network()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,187 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_server_type_info
short_description: Gather infos about the Hetzner Cloud server types.
version_added: "2.8"
description:
- Gather infos about your Hetzner Cloud server types.
- This module was called C(hcloud_server_type_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_server_type_facts).
Note that the M(hcloud_server_type_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_server_type_info)!
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the server type you want to get.
type: int
name:
description:
- The name of the server type you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud server type infos
hcloud_server_type_info:
register: output
- name: Print the gathered infos
debug:
var: output.hcloud_server_type_info
"""
RETURN = """
hcloud_server_type_info:
description: The server type infos as list
returned: always
type: complex
contains:
id:
description: Numeric identifier of the server type
returned: always
type: int
sample: 1937415
name:
description: Name of the server type
returned: always
type: str
sample: fsn1
description:
description: Detail description of the server type
returned: always
type: str
sample: Falkenstein DC Park 1
cores:
description: Number of cpu cores a server of this type will have
returned: always
type: int
sample: 1
memory:
description: Memory a server of this type will have in GB
returned: always
type: int
sample: 1
disk:
description: Disk size a server of this type will have in GB
returned: always
type: int
sample: 25
storage_type:
description: Type of server boot drive
returned: always
type: str
sample: local
cpu_type:
description: Type of cpu
returned: always
type: str
sample: shared
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudServerTypeInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_server_type_info")
self.hcloud_server_type_info = None
def _prepare_result(self):
tmp = []
for server_type in self.hcloud_server_type_info:
if server_type is not None:
tmp.append({
"id": to_native(server_type.id),
"name": to_native(server_type.name),
"description": to_native(server_type.description),
"cores": server_type.cores,
"memory": server_type.memory,
"disk": server_type.disk,
"storage_type": to_native(server_type.storage_type),
"cpu_type": to_native(server_type.cpu_type)
})
return tmp
def get_server_types(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_server_type_info = [self.client.server_types.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_server_type_info = [self.client.server_types.get_by_name(
self.module.params.get("name")
)]
else:
self.hcloud_server_type_info = self.client.server_types.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudServerTypeInfo.define_module()
is_old_facts = module._name == 'hcloud_server_type_facts'
if is_old_facts:
module.deprecate("The 'hcloud_server_type_info' module has been renamed to 'hcloud_server_type_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudServerTypeInfo(module)
hcloud.get_server_types()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_server_type_info': result['hcloud_server_type_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_server_type_info': result['hcloud_server_type_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,250 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_ssh_key
short_description: Create and manage ssh keys on the Hetzner Cloud.
version_added: "2.8"
description:
- Create, update and manage ssh keys on the Hetzner Cloud.
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the Hetzner Cloud ssh_key to manage.
- Only required if no ssh_key I(name) is given
type: int
name:
description:
- The Name of the Hetzner Cloud ssh_key to manage.
- Only required if no ssh_key I(id) is given or a ssh_key does not exists.
type: str
fingerprint:
description:
- The Fingerprint of the Hetzner Cloud ssh_key to manage.
- Only required if no ssh_key I(id) or I(name) is given.
type: str
labels:
description:
- User-defined labels (key-value pairs)
type: dict
public_key:
description:
- The Public Key to add.
- Required if ssh_key does not exists.
type: str
state:
description:
- State of the ssh_key.
default: present
choices: [ absent, present ]
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a basic ssh_key
hcloud_ssh_key:
name: my-ssh_key
public_key: "ssh-rsa AAAjjk76kgf...Xt"
state: present
- name: Create a ssh_key with labels
hcloud_ssh_key:
name: my-ssh_key
public_key: "ssh-rsa AAAjjk76kgf...Xt"
labels:
key: value
mylabel: 123
state: present
- name: Ensure the ssh_key is absent (remove if needed)
hcloud_ssh_key:
name: my-ssh_key
state: absent
"""
RETURN = """
hcloud_ssh_key:
description: The ssh_key instance
returned: Always
type: complex
contains:
id:
description: ID of the ssh_key
type: int
returned: Always
sample: 12345
name:
description: Name of the ssh_key
type: str
returned: Always
sample: my-ssh-key
fingerprint:
description: Fingerprint of the ssh_key
type: str
returned: Always
sample: b7:2f:30:a0:2f:6c:58:6c:21:04:58:61:ba:06:3b:2f
public_key:
description: Public key of the ssh_key
type: str
returned: Always
sample: "ssh-rsa AAAjjk76kgf...Xt"
labels:
description: User-defined labels (key-value pairs)
type: dict
returned: Always
sample:
key: value
mylabel: 123
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud.volumes.domain import Volume
from hcloud.ssh_keys.domain import SSHKey
from hcloud.ssh_keys.domain import Server
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudSSHKey(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_ssh_key")
self.hcloud_ssh_key = None
def _prepare_result(self):
return {
"id": to_native(self.hcloud_ssh_key.id),
"name": to_native(self.hcloud_ssh_key.name),
"fingerprint": to_native(self.hcloud_ssh_key.fingerprint),
"public_key": to_native(self.hcloud_ssh_key.public_key),
"labels": self.hcloud_ssh_key.labels,
}
def _get_ssh_key(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_ssh_key = self.client.ssh_keys.get_by_id(
self.module.params.get("id")
)
elif self.module.params.get("fingerprint") is not None:
self.hcloud_ssh_key = self.client.ssh_keys.get_by_fingerprint(
self.module.params.get("fingerprint")
)
elif self.module.params.get("name") is not None:
self.hcloud_ssh_key = self.client.ssh_keys.get_by_name(
self.module.params.get("name")
)
except APIException as e:
self.module.fail_json(msg=e.message)
def _create_ssh_key(self):
self.module.fail_on_missing_params(
required_params=["name", "public_key"]
)
params = {
"name": self.module.params.get("name"),
"public_key": self.module.params.get("public_key"),
"labels": self.module.params.get("labels")
}
if not self.module.check_mode:
self.client.ssh_keys.create(**params)
self._mark_as_changed()
self._get_ssh_key()
def _update_ssh_key(self):
name = self.module.params.get("name")
if name is not None and self.hcloud_ssh_key.name != name:
self.module.fail_on_missing_params(
required_params=["id"]
)
if not self.module.check_mode:
self.hcloud_ssh_key.update(name=name)
self._mark_as_changed()
labels = self.module.params.get("labels")
if labels is not None and self.hcloud_ssh_key.labels != labels:
if not self.module.check_mode:
self.hcloud_ssh_key.update(labels=labels)
self._mark_as_changed()
self._get_ssh_key()
def present_ssh_key(self):
self._get_ssh_key()
if self.hcloud_ssh_key is None:
self._create_ssh_key()
else:
self._update_ssh_key()
def delete_ssh_key(self):
self._get_ssh_key()
if self.hcloud_ssh_key is not None:
if not self.module.check_mode:
self.client.ssh_keys.delete(self.hcloud_ssh_key)
self._mark_as_changed()
self.hcloud_ssh_key = None
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
public_key={"type": "str"},
fingerprint={"type": "str"},
labels={"type": "dict"},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
required_one_of=[['id', 'name', 'fingerprint']],
required_if=[['state', 'present', ['name']]],
supports_check_mode=True,
)
def main():
module = AnsibleHcloudSSHKey.define_module()
hcloud = AnsibleHcloudSSHKey(module)
state = module.params.get("state")
if state == "absent":
hcloud.delete_ssh_key()
elif state == "present":
hcloud.present_ssh_key()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,179 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_ssh_key_info
short_description: Gather infos about your Hetzner Cloud ssh_keys.
version_added: "2.8"
description:
- Gather facts about your Hetzner Cloud ssh_keys.
- This module was called C(hcloud_ssh_key_facts) before Ansible 2.9, returning C(ansible_facts) and C(hcloud_ssh_key_facts).
Note that the M(hcloud_ssh_key_info) module no longer returns C(ansible_facts) and the value was renamed to C(hcloud_ssh_key_info)!
author:
- Christopher Schmitt (@cschmitt-hcloud)
options:
id:
description:
- The ID of the ssh key you want to get.
type: int
name:
description:
- The name of the ssh key you want to get.
type: str
fingerprint:
description:
- The fingerprint of the ssh key you want to get.
type: str
label_selector:
description:
- The label selector for the ssh key you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud sshkey infos
hcloud_ssh_key_info:
register: output
- name: Print the gathered infos
debug:
var: output.hcloud_ssh_key_info
"""
RETURN = """
hcloud_ssh_key_info:
description: The ssh key instances
returned: Always
type: complex
contains:
id:
description: Numeric identifier of the ssh_key
returned: always
type: int
sample: 1937415
name:
description: Name of the ssh_key
returned: always
type: str
sample: my-ssh-key
fingerprint:
description: Fingerprint of the ssh key
returned: always
type: str
sample: 0e:e0:bd:c7:2d:1f:69:49:94:44:91:f1:19:fd:35:f3
public_key:
description: The actual public key
returned: always
type: str
sample: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGpl/tnk74nnQJxxLAtutUApUZMRJxryKh7VXkNbd4g9 john@example.com"
labels:
description: User-defined labels (key-value pairs)
returned: always
type: dict
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudSSHKeyInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_ssh_key_info")
self.hcloud_ssh_key_info = None
def _prepare_result(self):
ssh_keys = []
for ssh_key in self.hcloud_ssh_key_info:
if ssh_key:
ssh_keys.append({
"id": to_native(ssh_key.id),
"name": to_native(ssh_key.name),
"fingerprint": to_native(ssh_key.fingerprint),
"public_key": to_native(ssh_key.public_key),
"labels": ssh_key.labels
})
return ssh_keys
def get_ssh_keys(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_ssh_key_info = [self.client.ssh_keys.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_ssh_key_info = [self.client.ssh_keys.get_by_name(
self.module.params.get("name")
)]
elif self.module.params.get("fingerprint") is not None:
self.hcloud_ssh_key_info = [self.client.ssh_keys.get_by_fingerprint(
self.module.params.get("fingerprint")
)]
elif self.module.params.get("label_selector") is not None:
self.hcloud_ssh_key_info = self.client.ssh_keys.get_all(
label_selector=self.module.params.get("label_selector"))
else:
self.hcloud_ssh_key_info = self.client.ssh_keys.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
fingerprint={"type": "str"},
label_selector={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudSSHKeyInfo.define_module()
is_old_facts = module._name == 'hcloud_ssh_key_facts'
if is_old_facts:
module.deprecate("The 'hcloud_ssh_key_facts' module has been renamed to 'hcloud_ssh_key_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudSSHKeyInfo(module)
hcloud.get_ssh_keys()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_ssh_key_facts': result['hcloud_ssh_key_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_ssh_key_info': result['hcloud_ssh_key_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,221 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_subnetwork
short_description: Manage cloud subnetworks on the Hetzner Cloud.
version_added: "2.9"
description:
- Create, update and delete cloud subnetworks on the Hetzner Cloud.
author:
- Lukas Kaemmerling (@lkaemmerling)
options:
network:
description:
- The ID or Name of the Hetzner Cloud Networks.
type: str
required: true
ip_range:
description:
- IP range of the subnetwork.
type: str
required: true
type:
description:
- Type of subnetwork.
type: str
required: true
network_zone:
description:
- Name of network zone.
type: str
required: true
state:
description:
- State of the subnetwork.
default: present
choices: [ absent, present ]
type: str
requirements:
- hcloud-python >= 1.3.0
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a basic subnetwork
hcloud_subnetwork:
network: my-network
ip_range: 10.0.0.0/16
network_zone: eu-central
type: server
state: present
- name: Ensure the subnetwork is absent (remove if needed)
hcloud_subnetwork:
network: my-network
ip_range: 10.0.0.0/8
network_zone: eu-central
type: server
state: absent
"""
RETURN = """
hcloud_subnetwork:
description: One Subnet of a Network
returned: always
type: complex
contains:
network:
description: Name of the Network
type: str
returned: always
sample: my-network
ip_range:
description: IP range of the Network
type: str
returned: always
sample: 10.0.0.0/8
type:
description: Type of subnetwork
type: str
returned: always
sample: server
network_zone:
description: Name of network zone
type: str
returned: always
sample: eu-central
gateway:
description: Gateway of the subnetwork
type: str
returned: always
sample: 10.0.0.1
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
from hcloud.networks.domain import NetworkSubnet
except ImportError:
APIException = None
NetworkSubnet = None
class AnsibleHcloudSubnetwork(Hcloud):
def __init__(self, module):
super(AnsibleHcloudSubnetwork, self).__init__(module, "hcloud_subnetwork")
self.hcloud_network = None
self.hcloud_subnetwork = None
def _prepare_result(self):
return {
"network": to_native(self.hcloud_network.name),
"ip_range": to_native(self.hcloud_subnetwork.ip_range),
"type": to_native(self.hcloud_subnetwork.type),
"network_zone": to_native(self.hcloud_subnetwork.network_zone),
"gateway": self.hcloud_subnetwork.gateway,
}
def _get_network(self):
try:
self.hcloud_network = self.client.networks.get_by_name(self.module.params.get("network"))
self.hcloud_subnetwork = None
except APIException as e:
self.module.fail_json(msg=e.message)
def _get_subnetwork(self):
subnet_ip_range = self.module.params.get("ip_range")
for subnetwork in self.hcloud_network.subnets:
if subnetwork.ip_range == subnet_ip_range:
self.hcloud_subnetwork = subnetwork
def _create_subnetwork(self):
subnet = NetworkSubnet(
ip_range=self.module.params.get("ip_range"),
type=self.module.params.get('type'),
network_zone=self.module.params.get('network_zone')
)
if not self.module.check_mode:
try:
self.hcloud_network.add_subnet(subnet=subnet).wait_until_finished()
except APIException as e:
self.module.fail_json(msg=e.message)
self._mark_as_changed()
self._get_network()
self._get_subnetwork()
def present_subnetwork(self):
self._get_network()
self._get_subnetwork()
if self.hcloud_subnetwork is None:
self._create_subnetwork()
def delete_subnetwork(self):
self._get_network()
self._get_subnetwork()
if self.hcloud_subnetwork is not None and self.hcloud_network is not None:
if not self.module.check_mode:
self.hcloud_network.delete_subnet(self.hcloud_subnetwork).wait_until_finished()
self._mark_as_changed()
self.hcloud_subnetwork = None
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
network={"type": "str", "required": True},
network_zone={"type": "str", "required": True},
type={"type": "str", "required": True},
ip_range={"type": "str", "required": True},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudSubnetwork.define_module()
hcloud = AnsibleHcloudSubnetwork(module)
state = module.params["state"]
if state == "absent":
hcloud.delete_subnetwork()
elif state == "present":
hcloud.present_subnetwork()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,344 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_volume
short_description: Create and manage block Volume on the Hetzner Cloud.
version_added: "2.8"
description:
- Create, update and attach/detach block Volume on the Hetzner Cloud.
author:
- Christopher Schmitt (@cschmitt-hcloud)
options:
id:
description:
- The ID of the Hetzner Cloud Block Volume to manage.
- Only required if no volume I(name) is given
type: int
name:
description:
- The Name of the Hetzner Cloud Block Volume to manage.
- Only required if no volume I(id) is given or a volume does not exists.
type: str
size:
description:
- The size of the Block Volume in GB.
- Required if volume does not yet exists.
type: int
automount:
description:
- Automatically mount the Volume.
type: bool
format:
description:
- Automatically Format the volume on creation
- Can only be used in case the Volume does not exists.
type: str
choices: [xfs, ext4]
location:
description:
- Location of the Hetzner Cloud Volume.
- Required if no I(server) is given and Volume does not exists.
type: str
server:
description:
- Server Name the Volume should be assigned to.
- Required if no I(location) is given and Volume does not exists.
type: str
delete_protection:
description:
- Protect the Volume for deletion.
type: bool
version_added: "2.10"
labels:
description:
- User-defined key-value pairs.
type: dict
state:
description:
- State of the Volume.
default: present
choices: [absent, present]
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Create a Volume
hcloud_volume:
name: my-volume
location: fsn1
size: 100
state: present
- name: Create a Volume and format it with ext4
hcloud_volume:
name: my-volume
location: fsn
format: ext4
size: 100
state: present
- name: Mount a existing Volume and automount
hcloud_volume:
name: my-volume
server: my-server
automount: yes
state: present
- name: Mount a existing Volume and automount
hcloud_volume:
name: my-volume
server: my-server
automount: yes
state: present
- name: Ensure the Volume is absent (remove if needed)
hcloud_volume:
name: my-volume
state: absent
"""
RETURN = """
hcloud_volume:
description: The block Volume
returned: Always
type: complex
contains:
id:
description: ID of the Volume
type: int
returned: Always
sample: 12345
name:
description: Name of the Volume
type: str
returned: Always
sample: my-volume
size:
description: Size in GB of the Volume
type: int
returned: Always
sample: 1337
linux_device:
description: Path to the device that contains the Volume.
returned: always
type: str
sample: /dev/disk/by-id/scsi-0HC_Volume_12345
version_added: "2.10"
location:
description: Location name where the Volume is located at
type: str
returned: Always
sample: "fsn1"
labels:
description: User-defined labels (key-value pairs)
type: dict
returned: Always
sample:
key: value
mylabel: 123
server:
description: Server name where the Volume is attached to
type: str
returned: Always
sample: "my-server"
delete_protection:
description: True if Volume is protected for deletion
type: bool
returned: always
sample: false
version_added: "2.10"
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud.volumes.domain import Volume
from hcloud.servers.domain import Server
import hcloud
except ImportError:
pass
class AnsibleHcloudVolume(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_volume")
self.hcloud_volume = None
def _prepare_result(self):
server_name = None
if self.hcloud_volume.server is not None:
server_name = self.hcloud_volume.server.name
return {
"id": to_native(self.hcloud_volume.id),
"name": to_native(self.hcloud_volume.name),
"size": self.hcloud_volume.size,
"location": to_native(self.hcloud_volume.location.name),
"labels": self.hcloud_volume.labels,
"server": to_native(server_name),
"linux_device": to_native(self.hcloud_volume.linux_device),
"delete_protection": self.hcloud_volume.protection["delete"],
}
def _get_volume(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_volume = self.client.volumes.get_by_id(
self.module.params.get("id")
)
else:
self.hcloud_volume = self.client.volumes.get_by_name(
self.module.params.get("name")
)
except hcloud.APIException as e:
self.module.fail_json(msg=e.message)
def _create_volume(self):
self.module.fail_on_missing_params(
required_params=["name", "size"]
)
params = {
"name": self.module.params.get("name"),
"size": self.module.params.get("size"),
"automount": self.module.params.get("automount"),
"format": self.module.params.get("format"),
"labels": self.module.params.get("labels")
}
if self.module.params.get("server") is not None:
params['server'] = self.client.servers.get_by_name(self.module.params.get("server"))
elif self.module.params.get("location") is not None:
params['location'] = self.client.locations.get_by_name(self.module.params.get("location"))
else:
self.module.fail_json(msg="server or location is required")
if not self.module.check_mode:
resp = self.client.volumes.create(**params)
resp.action.wait_until_finished()
[action.wait_until_finished() for action in resp.next_actions]
self._mark_as_changed()
self._get_volume()
def _update_volume(self):
try:
size = self.module.params.get("size")
if size:
if self.hcloud_volume.size < size:
if not self.module.check_mode:
self.hcloud_volume.resize(size).wait_until_finished()
self._mark_as_changed()
elif self.hcloud_volume.size > size:
self.module.warn("Shrinking of volumes is not supported")
server_name = self.module.params.get("server")
if server_name:
server = self.client.servers.get_by_name(server_name)
if self.hcloud_volume.server is None or self.hcloud_volume.server.name != server.name:
if not self.module.check_mode:
automount = self.module.params.get("automount", False)
self.hcloud_volume.attach(server, automount=automount).wait_until_finished()
self._mark_as_changed()
else:
if self.hcloud_volume.server is not None:
if not self.module.check_mode:
self.hcloud_volume.detach().wait_until_finished()
self._mark_as_changed()
labels = self.module.params.get("labels")
if labels is not None and labels != self.hcloud_volume.labels:
if not self.module.check_mode:
self.hcloud_volume.update(labels=labels)
self._mark_as_changed()
delete_protection = self.module.params.get("delete_protection")
if delete_protection is not None and delete_protection != self.hcloud_volume.protection["delete"]:
if not self.module.check_mode:
self.hcloud_volume.change_protection(delete=delete_protection).wait_until_finished()
self._mark_as_changed()
self._get_volume()
except hcloud.APIException as e:
self.module.fail_json(msg=e.message)
def present_volume(self):
self._get_volume()
if self.hcloud_volume is None:
self._create_volume()
else:
self._update_volume()
def delete_volume(self):
try:
self._get_volume()
if self.hcloud_volume is not None:
if not self.module.check_mode:
self.client.volumes.delete(self.hcloud_volume)
self._mark_as_changed()
self.hcloud_volume = None
except hcloud.APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
size={"type": "int"},
location={"type": "str"},
server={"type": "str"},
labels={"type": "dict"},
automount={"type": "bool", "default": False},
format={"type": "str",
"choices": ['xfs', 'ext4'],
},
delete_protection={"type": "bool"},
state={
"choices": ["absent", "present"],
"default": "present",
},
**Hcloud.base_module_arguments()
),
required_one_of=[['id', 'name']],
mutually_exclusive=[["location", "server"]],
supports_check_mode=True,
)
def main():
module = AnsibleHcloudVolume.define_module()
hcloud = AnsibleHcloudVolume(module)
state = module.params.get("state")
if state == "absent":
module.fail_on_missing_params(
required_params=["name"]
)
hcloud.delete_volume()
else:
hcloud.present_volume()
module.exit_json(**hcloud.get_result())
if __name__ == "__main__":
main()

@ -1,196 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
"metadata_version": "1.1",
"status": ["preview"],
"supported_by": "community",
}
DOCUMENTATION = """
---
module: hcloud_volume_info
short_description: Gather infos about your Hetzner Cloud Volumes.
version_added: "2.8"
description:
- Gather infos about your Hetzner Cloud Volumes.
author:
- Lukas Kaemmerling (@LKaemmerling)
options:
id:
description:
- The ID of the Volume you want to get.
type: int
name:
description:
- The name of the Volume you want to get.
type: str
label_selector:
description:
- The label selector for the Volume you want to get.
type: str
extends_documentation_fragment: hcloud
"""
EXAMPLES = """
- name: Gather hcloud Volume infos
hcloud_volume_info:
register: output
- name: Print the gathered infos
debug:
var: output.hcloud_volume_info
"""
RETURN = """
hcloud_volume_info:
description: The Volume infos as list
returned: always
type: complex
contains:
id:
description: Numeric identifier of the Volume
returned: always
type: int
sample: 1937415
name:
description: Name of the Volume
returned: always
type: str
sample: my-volume
size:
description: Size of the Volume
returned: always
type: str
sample: 10
linux_device:
description: Path to the device that contains the Volume.
returned: always
type: str
sample: /dev/disk/by-id/scsi-0HC_Volume_12345
version_added: "2.10"
location:
description: Name of the location where the Volume resides in
returned: always
type: str
sample: fsn1
server:
description: Name of the server where the Volume is attached to
returned: always
type: str
sample: my-server
delete_protection:
description: True if the Volume is protected for deletion
returned: always
type: bool
version_added: "2.10"
labels:
description: User-defined labels (key-value pairs)
returned: always
type: dict
"""
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_native
from ansible.module_utils.hcloud import Hcloud
try:
from hcloud import APIException
except ImportError:
pass
class AnsibleHcloudVolumeInfo(Hcloud):
def __init__(self, module):
Hcloud.__init__(self, module, "hcloud_volume_info")
self.hcloud_volume_info = None
def _prepare_result(self):
tmp = []
for volume in self.hcloud_volume_info:
if volume is not None:
server_name = None
if volume.server is not None:
server_name = volume.server.name
tmp.append({
"id": to_native(volume.id),
"name": to_native(volume.name),
"size": volume.size,
"location": to_native(volume.location.name),
"labels": volume.labels,
"server": to_native(server_name),
"linux_device": to_native(volume.linux_device),
"delete_protection": volume.protection["delete"],
})
return tmp
def get_volumes(self):
try:
if self.module.params.get("id") is not None:
self.hcloud_volume_info = [self.client.volumes.get_by_id(
self.module.params.get("id")
)]
elif self.module.params.get("name") is not None:
self.hcloud_volume_info = [self.client.volumes.get_by_name(
self.module.params.get("name")
)]
elif self.module.params.get("label_selector") is not None:
self.hcloud_volume_info = self.client.volumes.get_all(
label_selector=self.module.params.get("label_selector"))
else:
self.hcloud_volume_info = self.client.volumes.get_all()
except APIException as e:
self.module.fail_json(msg=e.message)
@staticmethod
def define_module():
return AnsibleModule(
argument_spec=dict(
id={"type": "int"},
name={"type": "str"},
label_selector={"type": "str"},
**Hcloud.base_module_arguments()
),
supports_check_mode=True,
)
def main():
module = AnsibleHcloudVolumeInfo.define_module()
is_old_facts = module._name == 'hcloud_volume_facts'
if is_old_facts:
module.deprecate("The 'hcloud_volume_facts' module has been renamed to 'hcloud_volume_info', "
"and the renamed one no longer returns ansible_facts", version='2.13')
hcloud = AnsibleHcloudVolumeInfo(module)
hcloud.get_volumes()
result = hcloud.get_result()
if is_old_facts:
ansible_info = {
'hcloud_volume_facts': result['hcloud_volume_info']
}
module.exit_json(ansible_facts=ansible_info)
else:
ansible_info = {
'hcloud_volume_info': result['hcloud_volume_info']
}
module.exit_json(**ansible_info)
if __name__ == "__main__":
main()

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
class ModuleDocFragment(object):
DOCUMENTATION = '''
options:
api_token:
description:
- This is the API Token for the Hetzner Cloud.
required: True
type: str
endpoint:
description:
- This is the API Endpoint for the Hetzner Cloud.
default: https://api.hetzner.cloud/v1
type: str
requirements:
- hcloud-python >= 1.0.0
seealso:
- name: Documentation for Hetzner Cloud API
description: Complete reference for the Hetzner Cloud API.
link: https://docs.hetzner.cloud/
'''

@ -1,262 +0,0 @@
# Copyright (c) 2019 Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = r"""
name: hcloud
plugin_type: inventory
author:
- Lukas Kaemmerling (@lkaemmerling)
short_description: Ansible dynamic inventory plugin for the Hetzner Cloud.
version_added: "2.8"
requirements:
- python >= 2.7
- hcloud-python >= 1.0.0
description:
- Reads inventories from the Hetzner Cloud API.
- Uses a YAML configuration file that ends with hcloud.(yml|yaml).
extends_documentation_fragment:
- constructed
options:
plugin:
description: marks this as an instance of the "hcloud" plugin
required: true
choices: ["hcloud"]
token:
description: The Hetzner Cloud API Token.
required: true
env:
- name: HCLOUD_TOKEN
connect_with:
description: Connect to the server using the value from this field.
default: public_ipv4
type: str
choices:
- public_ipv4
- hostname
- ipv4_dns_ptr
locations:
description: Populate inventory with instances in this location.
default: []
type: list
required: false
types:
description: Populate inventory with instances with this type.
default: []
type: list
required: false
images:
description: Populate inventory with instances with this image name, only available for system images.
default: []
type: list
required: false
label_selector:
description: Populate inventory with instances with this label.
default: ""
type: str
required: false
network:
description: Populate inventory with instances which are attached to this network name or ID.
default: ""
type: str
required: false
"""
EXAMPLES = r"""
# Minimal example. `HCLOUD_TOKEN` is exposed in environment.
plugin: hcloud
# Example with locations, types, groups and token
plugin: hcloud
token: foobar
locations:
- nbg1
types:
- cx11
# Group by a location with prefix e.g. "hcloud_location_nbg1"
# and image_os_flavor without prefix and separator e.g. "ubuntu"
# and status with prefix e.g. "server_status_running"
plugin: hcloud
keyed_groups:
- key: location
prefix: hcloud_location
- key: image_os_flavor
separator: ""
- key: status
prefix: server_status
"""
import os
from ansible.errors import AnsibleError
from ansible.module_utils._text import to_native
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable
from ansible.release import __version__
try:
from hcloud import hcloud
except ImportError:
raise AnsibleError("The Hetzner Cloud dynamic inventory plugin requires hcloud-python.")
class InventoryModule(BaseInventoryPlugin, Constructable):
NAME = "hcloud"
def _configure_hcloud_client(self):
self.api_token = self.get_option("token")
if self.api_token is None:
raise AnsibleError(
"Please specify a token, via the option token or via environment variable HCLOUD_TOKEN")
self.endpoint = os.getenv("HCLOUD_ENDPOINT") or "https://api.hetzner.cloud/v1"
self.client = hcloud.Client(token=self.api_token,
api_endpoint=self.endpoint,
application_name="ansible-inventory",
application_version=__version__)
def _test_hcloud_token(self):
try:
# We test the API Token against the location API, because this is the API with the smallest result
# and not controllable from the customer.
self.client.locations.get_all()
except hcloud.APIException:
raise AnsibleError("Invalid Hetzner Cloud API Token.")
def _get_servers(self):
if len(self.get_option("label_selector")) > 0:
self.servers = self.client.servers.get_all(label_selector=self.get_option("label_selector"))
else:
self.servers = self.client.servers.get_all()
def _filter_servers(self):
if self.get_option("network"):
try:
self.network = self.client.networks.get_by_name(self.get_option("network"))
if self.network is None:
self.network = self.client.networks.get_by_id(self.get_option("network"))
except hcloud.APIException:
raise AnsibleError(
"The given network is not found.")
tmp = []
for server in self.servers:
for server_private_network in server.private_net:
if server_private_network.network.id == self.network.id:
tmp.append(server)
self.servers = tmp
if self.get_option("locations"):
tmp = []
for server in self.servers:
if server.datacenter.location.name in self.get_option("locations"):
tmp.append(server)
self.servers = tmp
if self.get_option("types"):
tmp = []
for server in self.servers:
if server.server_type.name in self.get_option("types"):
tmp.append(server)
self.servers = tmp
if self.get_option("images"):
tmp = []
for server in self.servers:
if server.image is not None and server.image.os_flavor in self.get_option("images"):
tmp.append(server)
self.servers = tmp
def _set_server_attributes(self, server):
self.inventory.set_variable(server.name, "id", to_native(server.id))
self.inventory.set_variable(server.name, "name", to_native(server.name))
self.inventory.set_variable(server.name, "status", to_native(server.status))
self.inventory.set_variable(server.name, "type", to_native(server.server_type.name))
# Network
self.inventory.set_variable(server.name, "ipv4", to_native(server.public_net.ipv4.ip))
self.inventory.set_variable(server.name, "ipv6_network", to_native(server.public_net.ipv6.network))
self.inventory.set_variable(server.name, "ipv6_network_mask", to_native(server.public_net.ipv6.network_mask))
if self.get_option("network"):
for server_private_network in server.private_net:
if server_private_network.network.id == self.network.id:
self.inventory.set_variable(server.name, "private_ipv4", to_native(server_private_network.ip))
if self.get_option("connect_with") == "public_ipv4":
self.inventory.set_variable(server.name, "ansible_host", to_native(server.public_net.ipv4.ip))
elif self.get_option("connect_with") == "hostname":
self.inventory.set_variable(server.name, "ansible_host", to_native(server.name))
elif self.get_option("connect_with") == "ipv4_dns_ptr":
self.inventory.set_variable(server.name, "ansible_host", to_native(server.public_net.ipv4.dns_ptr))
elif self.get_option("connect_with") == "private_ipv4":
if self.get_option("network"):
for server_private_network in server.private_net:
if server_private_network.network.id == self.network.id:
self.inventory.set_variable(server.name, "ansible_host", to_native(server_private_network.ip))
else:
raise AnsibleError(
"You can only connect via private IPv4 if you specify a network")
# Server Type
if server.image is not None and server.image.name is not None:
self.inventory.set_variable(server.name, "server_type", to_native(server.image.name))
else:
self.inventory.set_variable(server.name, "server_type", to_native("No Image name found."))
# Datacenter
self.inventory.set_variable(server.name, "datacenter", to_native(server.datacenter.name))
self.inventory.set_variable(server.name, "location", to_native(server.datacenter.location.name))
# Image
if server.image is not None:
self.inventory.set_variable(server.name, "image_id", to_native(server.image.id))
self.inventory.set_variable(server.name, "image_os_flavor", to_native(server.image.os_flavor))
if server.image.name is not None:
self.inventory.set_variable(server.name, "image_name", to_native(server.image.name))
else:
self.inventory.set_variable(server.name, "image_name", to_native(server.image.description))
else:
self.inventory.set_variable(server.name, "image_id", to_native("No Image ID found"))
self.inventory.set_variable(server.name, "image_name", to_native("No Image Name found"))
self.inventory.set_variable(server.name, "image_os_flavor", to_native("No Image OS Flavor found"))
# Labels
self.inventory.set_variable(server.name, "labels", dict(server.labels))
def verify_file(self, path):
"""Return the possibly of a file being consumable by this plugin."""
return (
super(InventoryModule, self).verify_file(path) and
path.endswith((self.NAME + ".yaml", self.NAME + ".yml"))
)
def parse(self, inventory, loader, path, cache=True):
super(InventoryModule, self).parse(inventory, loader, path, cache)
self._read_config_data(path)
self._configure_hcloud_client()
self._test_hcloud_token()
self._get_servers()
self._filter_servers()
# Add a top group 'hcloud'
self.inventory.add_group(group="hcloud")
for server in self.servers:
self.inventory.add_host(server.name, group="hcloud")
self._set_server_attributes(server)
# Use constructed if applicable
strict = self.get_option('strict')
# Composed variables
self._set_composite_vars(self.get_option('compose'), self.inventory.get_host(server.name).get_vars(), server.name, strict=strict)
# Complex groups based on jinja2 conditionals, hosts that meet the conditional are added to group
self._add_host_to_composed_groups(self.get_option('groups'), {}, server.name, strict=strict)
# Create groups based on variable values and add the corresponding hosts to it
self._add_host_to_keyed_groups(self.get_option('keyed_groups'), {}, server.name, strict=strict)

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,6 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_datacenter_name: "fsn1-dc14"
hcloud_datacenter_id: 4
hcloud_location_name: "fsn1"

@ -1,40 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: test gather hcloud datacenter infos
hcloud_datacenter_info:
register: hcloud_datacenters
- name: verify test gather hcloud datacenter infos
assert:
that:
- hcloud_datacenters.hcloud_datacenter_info| list | count == 3
- name: test gather hcloud datacenter infos in check mode
hcloud_datacenter_info:
register: hcloud_datacenters
check_mode: yes
- name: verify test gather hcloud datacenter infos in check mode
assert:
that:
- hcloud_datacenters.hcloud_datacenter_info| list | count == 3
- name: test gather hcloud datacenter infos with correct name
hcloud_datacenter_info:
name: "{{hcloud_datacenter_name}}"
register: hcloud_datacenter
- name: verify test gather hcloud datacenter with correct name
assert:
that:
- hcloud_datacenter.hcloud_datacenter_info|selectattr('name','equalto','{{ hcloud_datacenter_name }}') |selectattr('location','equalto','{{ hcloud_location_name }}') | list | count == 1
- name: test gather hcloud datacenter infos with correct id
hcloud_datacenter_info:
id: "{{hcloud_datacenter_id}}"
register: hcloud_datacenter
- name: verify test gather hcloud datacenter with correct id
assert:
that:
- hcloud_datacenter.hcloud_datacenter_info|selectattr('name','equalto','{{ hcloud_datacenter_name }}') | list | count == 1

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,6 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_floating_ip_name: "{{hcloud_prefix}}-integration"
hcloud_server_name: "{{hcloud_prefix}}-fip-tests"

@ -1,384 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup server
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: cx11
image: ubuntu-18.04
state: started
location: "fsn1"
register: main_server
- name: verify setup server
assert:
that:
- main_server is changed
- name: setup another server
hcloud_server:
name: "{{ hcloud_server_name }}2"
server_type: cx11
image: ubuntu-18.04
state: started
register: main_server2
- name: verify setup another server
assert:
that:
- main_server2 is changed
- name: test missing type parameter on create Floating IP
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
register: result
ignore_errors: yes
- name: verify fail test missing type parameter on create Floating IP
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: type"'
- name: test missing required parameters on create Floating IP
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
register: result
ignore_errors: yes
- name: verify fail test missing required parameters on create Floating IP
assert:
that:
- result is failed
- 'result.msg == "one of the following is required: home_location, server"'
- name: test missing type parameter on delete Floating IP
hcloud_floating_ip:
type: ipv4
home_location: "fsn1"
state: "absent"
register: result
ignore_errors: yes
- name: verify fail test missing type parameter on delete Floating IP
assert:
that:
- result is failed
- 'result.msg == "one of the following is required: id, name"'
- name: test create Floating IP with check mode
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "Web Server"
type: ipv4
home_location: "fsn1"
register: floatingIP
check_mode: yes
- name: verify test create Floating IP with check mode
assert:
that:
- floatingIP is changed
- name: test create Floating IP
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "Web Server"
type: ipv4
home_location: "fsn1"
register: floatingIP
- name: verify test create Floating IP
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.name ==hcloud_floating_ip_name
- floatingIP.hcloud_floating_ip.description == "Web Server"
- floatingIP.hcloud_floating_ip.home_location == "fsn1"
- name: test create Floating IP idempotency
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "Web Server"
type: ipv4
home_location: "fsn1"
register: floatingIP
- name: verify test create Floating IP idempotency
assert:
that:
- floatingIP is not changed
- name: test update Floating IP with check mode
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "changed-description"
type: ipv4
home_location: "fsn1"
check_mode: yes
register: floatingIP
- name: verify test create Floating IP with check mode
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.description == "Web Server"
- name: test update Floating IP
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "changed-description"
type: ipv4
home_location: "fsn1"
labels:
key: value
register: floatingIP
- name: verify test update Floating IP
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.description == "changed-description"
- name: test update Floating IP idempotency
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "changed-description"
type: ipv4
home_location: "fsn1"
labels:
key: value
register: floatingIP
- name: verify test update Floating IP idempotency
assert:
that:
- floatingIP is not changed
- name: test update Floating IP with same labels
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
home_location: "fsn1"
labels:
key: value
register: floatingIP
- name: verify test update Floating IP with same labels
assert:
that:
- floatingIP is not changed
- name: test update Floating IP with other labels
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
home_location: "fsn1"
labels:
key: value
other: label
register: floatingIP
- name: verify test update Floating IP with other labels
assert:
that:
- floatingIP is changed
- name: test update Floating IP with other labels in different order
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
home_location: "fsn1"
labels:
other: label
key: value
register: floatingIP
- name: verify test update Floating IP with other labels in different order
assert:
that:
- floatingIP is not changed
- name: test assign Floating IP with checkmode
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "changed-description"
type: ipv4
server: "{{ main_server.hcloud_server.name }}"
check_mode: yes
register: floatingIP
- name: verify test assign Floating IP with checkmode
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.server != "{{ main_server.hcloud_server.name }}"
- name: test assign Floating IP
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
description: "changed-description"
type: ipv4
server: "{{ main_server.hcloud_server.name }}"
register: floatingIP
- name: verify test assign Floating IP
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.server == "{{ main_server.hcloud_server.name }}"
- name: test unassign Floating IP
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
home_location: "fsn1"
register: floatingIP
- name: verify test unassign Floating IP
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.server != "{{ main_server.hcloud_server.name }}"
- name: test unassign Floating IP idempotency
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
home_location: "fsn1"
register: floatingIP
- name: verify test unassign Floating IPidempotency
assert:
that:
- floatingIP is not changed
- name: test assign Floating IP again
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
server: "{{ main_server.hcloud_server.name }}"
register: floatingIP
- name: verify test assign Floating IP again
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.server == "{{ main_server.hcloud_server.name }}"
- name: test already assigned Floating IP assign without force
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
server: "{{ main_server2.hcloud_server.name }}"
register: floatingIP
- name: verify test already assigned Floating IP assign without force
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.server == "{{ main_server.hcloud_server.name }}"
- name: test already assigned Floating IP assign with force
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
force: yes
server: "{{ main_server2.hcloud_server.name }}"
register: floatingIP
- name: verify test already assigned Floating IP assign with force
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.server == "{{ main_server2.hcloud_server.name }}"
- name: test update Floating IP delete protection
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
delete_protection: true
register: floatingIP
- name: verify update Floating IP delete protection
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.delete_protection is sameas true
- name: test update Floating IP delete protection idempotency
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
delete_protection: true
register: floatingIP
- name: verify update Floating IP delete protection idempotency
assert:
that:
- floatingIP is not changed
- floatingIP.hcloud_floating_ip.delete_protection is sameas true
- name: test Floating IP without delete protection set to be idempotent
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
register: floatingIP
- name: verify Floating IP without delete protection set to be idempotent
assert:
that:
- floatingIP is not changed
- floatingIP.hcloud_floating_ip.delete_protection is sameas true
- name: test delete Floating IP fails if it is protected
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
state: "absent"
register: result
ignore_errors: yes
- name: verify test delete floating ip
assert:
that:
- result is failed
- 'result.msg == "Floating IP deletion is protected"'
- name: test update Floating IP delete protection
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv4
delete_protection: false
register: floatingIP
- name: verify update Floating IP delete protection
assert:
that:
- floatingIP is changed
- floatingIP.hcloud_floating_ip.delete_protection is sameas false
- name: test delete floating ip
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
state: "absent"
register: result
- name: verify test delete floating ip
assert:
that:
- result is changed
- name: test create ipv6 floating ip
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
type: ipv6
home_location: "fsn1"
state: "present"
register: result
- name: verify test create ipv6 floating ip
assert:
that:
- result is changed
- name: test delete ipv6 floating ip
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
state: "absent"
register: result
- name: verify test delete ipv6 floating ip
assert:
that:
- result is changed
- name: cleanup
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is changed
- name: cleanup another server
hcloud_server:
name: "{{ main_server2.hcloud_server.name }}"
state: absent
register: result
- name: verify cleanup another server
assert:
that:
- result is changed

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_floating_ip_name: "{{hcloud_prefix}}-integration"

@ -1,87 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup ensure floating ip is absent
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
state: absent
- name: setup floating ip
hcloud_floating_ip:
name: "{{ hcloud_floating_ip_name }}"
home_location: "fsn1"
type: ipv4
labels:
key: value
register: test_floating_ip
- name: verify setup floating ip
assert:
that:
- test_floating_ip is changed
- name: test gather hcloud floating ip infos
hcloud_floating_ip_info:
register: hcloud_floating_ips
- name: verify test gather hcloud floating ip infos
assert:
that:
- hcloud_floating_ips.hcloud_floating_ip_info| list | count >= 1
- name: test gather hcloud floating ip infos in check mode
hcloud_floating_ip_info:
check_mode: yes
register: hcloud_floating_ips
- name: verify test gather hcloud floating ip infos in check mode
assert:
that:
- hcloud_floating_ips.hcloud_floating_ip_info| list | count >= 1
- name: test gather hcloud floating ip infos with correct label selector
hcloud_floating_ip_info:
label_selector: "key=value"
register: hcloud_floating_ips
- name: verify test gather hcloud floating ip with correct label selector
assert:
that:
- hcloud_floating_ips.hcloud_floating_ip_info|selectattr('name','equalto','{{ test_floating_ip.hcloud_floating_ip.name }}') | list | count == 1
- name: test gather hcloud floating ip infos with wrong label selector
hcloud_floating_ip_info:
label_selector: "key!=value"
register: hcloud_floating_ips
- name: verify test gather hcloud floating ip with wrong label selector
assert:
that:
- hcloud_floating_ips.hcloud_floating_ip_info | list | count == 0
- name: test gather hcloud floating ip infos with correct id
hcloud_floating_ip_info:
id: "{{test_floating_ip.hcloud_floating_ip.id}}"
register: hcloud_floating_ips
- name: verify test gather hcloud floating ip with correct id
assert:
that:
- hcloud_floating_ips.hcloud_floating_ip_info|selectattr('name','equalto','{{ test_floating_ip.hcloud_floating_ip.name }}') | list | count == 1
- name: test gather hcloud floating ip infos with wrong id
hcloud_floating_ip_info:
id: "{{test_floating_ip.hcloud_floating_ip.id}}1"
register: result
ignore_errors: yes
- name: verify test gather hcloud floating ip with wrong id
assert:
that:
- result is failed
- name: cleanup
hcloud_floating_ip:
id: "{{ test_floating_ip.hcloud_floating_ip.id }}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,6 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_test_image_name: "always-there-snapshot"
hcloud_test_image_id: 10164049

@ -1,62 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: test gather hcloud image infos with type system
hcloud_image_info:
register: hcloud_images
- name: verify test gather hcloud image infos in check mode
assert:
that:
- hcloud_images.hcloud_image_info| list | count > 2
- name: test gather hcloud image infos in check mode
hcloud_image_info:
check_mode: yes
register: hcloud_images
- name: verify test gather hcloud image infos in check mode
assert:
that:
- hcloud_images.hcloud_image_info| list | count > 2
- name: test gather hcloud image infos with correct label selector
hcloud_image_info:
label_selector: "key=value"
type: snapshot
register: hcloud_images
- name: verify test gather hcloud image with correct label selector
assert:
that:
- hcloud_images.hcloud_image_info|selectattr('description','equalto','{{ hcloud_test_image_name }}') | list | count == 1
- name: test gather hcloud image infos with wrong label selector
hcloud_image_info:
label_selector: "key!=value"
type: snapshot
register: hcloud_images
- name: verify test gather hcloud image with wrong label selector
assert:
that:
- hcloud_images.hcloud_image_info | list | count == 0
- name: test gather hcloud image infos with correct id
hcloud_image_info:
id: "{{hcloud_test_image_id}}"
type: snapshot
register: hcloud_images
- name: verify test gather hcloud image with correct id
assert:
that:
- hcloud_images.hcloud_image_info|selectattr('description','equalto','{{ hcloud_test_image_name }}') | list | count == 1
- name: test gather hcloud image infos with wrong id
hcloud_image_info:
id: "{{hcloud_test_image_id}}1"
type: snapshot
ignore_errors: yes
register: result
- name: verify test gather hcloud image with wrong id
assert:
that:
- result is failed

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_location_name: "fsn1"
hcloud_location_id: 1

@ -1,57 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: test gather hcloud location infos
hcloud_location_info:
register: hcloud_location
- name: verify test gather hcloud location infos
assert:
that:
- hcloud_location.hcloud_location_info | list | count == 3
- name: test gather hcloud location infos in check mode
hcloud_location_info:
check_mode: yes
register: hcloud_location
- name: verify test gather hcloud location infos in check mode
assert:
that:
- hcloud_location.hcloud_location_info | list | count == 3
- name: test gather hcloud location infos with correct name
hcloud_location_info:
name: "{{hcloud_location_name}}"
register: hcloud_location
- name: verify test gather hcloud location with correct name
assert:
that:
- hcloud_location.hcloud_location_info|selectattr('name','equalto','{{ hcloud_location_name }}') | list | count == 1
- name: test gather hcloud location infos with wrong name
hcloud_location_info:
name: "{{hcloud_location_name}}1"
register: hcloud_location
- name: verify test gather hcloud location with wrong name
assert:
that:
- hcloud_location.hcloud_location_info | list | count == 0
- name: test gather hcloud location infos with correct id
hcloud_location_info:
id: "{{hcloud_location_id}}"
register: hcloud_location
- name: verify test gather hcloud location with correct id
assert:
that:
- hcloud_location.hcloud_location_info|selectattr('name','equalto','{{ hcloud_location_name }}') | list | count == 1
- name: test gather hcloud location infos with wrong id
hcloud_location_info:
name: "4711"
register: hcloud_location
- name: verify test gather hcloud location with wrong id
assert:
that:
- hcloud_location.hcloud_location_info | list | count == 0

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group1

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_network_name: "{{hcloud_prefix}}-integ"

@ -1,169 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup
hcloud_network:
name: "{{ hcloud_network_name }}"
state: absent
register: result
- name: verify setup
assert:
that:
- result is success
- name: test missing ip_range parameter on create Network
hcloud_network:
name: "{{hcloud_network_name}}"
register: result
ignore_errors: yes
- name: verify fail missing ip_range parameter on create Network result
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: ip_range"'
- name: test create Network with check mode
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/16"
register: result
check_mode: yes
- name: verify create Network with check mode result
assert:
that:
- result is changed
- name: test create Network
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/16"
register: network
- name: verify test create Network result
assert:
that:
- network is changed
- network.hcloud_network.name == "{{hcloud_network_name}}"
- network.hcloud_network.ip_range == "10.0.0.0/16"
- name: test create Network idempotence
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/16"
register: network
- name: verify test create network
assert:
that:
- network is not changed
- name: test update Network label
hcloud_network:
name: "{{hcloud_network_name}}"
labels:
key: value
register: network
- name: verify test update Network label
assert:
that:
- network is changed
- network.hcloud_network.labels.key == "value"
- name: test update Network label idempotency
hcloud_network:
name: "{{hcloud_network_name}}"
labels:
key: value
register: network
- name: verify test update Network label idempotency
assert:
that:
- network is not changed
- name: test update Network ip range
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/8"
register: network
- name: verify test update Network ip range
assert:
that:
- network is changed
- network.hcloud_network.ip_range == "10.0.0.0/8"
- name: test update Network ip range idempotency
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/8"
register: network
- name: verify test update Network ip range idempotency
assert:
that:
- network is not changed
- name: test update Network delete protection
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/8"
delete_protection: true
register: network
- name: verify test update Network delete protection
assert:
that:
- network is changed
- network.hcloud_network.delete_protection is sameas true
- name: test update Network delete protection idempotency
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/8"
delete_protection: true
register: network
- name: verify test update Network delete protection idempotency
assert:
that:
- network is not changed
- network.hcloud_network.delete_protection is sameas true
- name: test Network without delete protection set to be idempotent
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/8"
register: network
- name: verify test Network without delete protection set to be idempotent
assert:
that:
- network is not changed
- network.hcloud_network.delete_protection is sameas true
- name: test delete Network fails if it is protected
hcloud_network:
name: "{{hcloud_network_name}}"
state: absent
ignore_errors: yes
register: result
- name: verify delete Network
assert:
that:
- result is failed
- 'result.msg == "network deletion is protected"'
- name: test update Network delete protection
hcloud_network:
name: "{{hcloud_network_name}}"
ip_range: "10.0.0.0/8"
delete_protection: false
register: network
- name: verify test update Network delete protection
assert:
that:
- network is changed
- network.hcloud_network.delete_protection is sameas false
- name: test delete Network
hcloud_network:
name: "{{hcloud_network_name}}"
state: absent
register: result
- name: verify delete Network
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group1

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_network_name: "{{hcloud_prefix}}-integration"

@ -1,117 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup ensure network is absent
hcloud_network:
name: "{{ hcloud_network_name }}"
state: absent
register: result
- name: create network
hcloud_network:
name: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/16"
labels:
key: value
register: main_network
- name: verify create network
assert:
that:
- main_network is changed
- main_network.hcloud_network.name == "{{ hcloud_network_name }}"
- main_network.hcloud_network.ip_range == "10.0.0.0/16"
- name: create subnetwork
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
type: server
network_zone: eu-central
ip_range: "10.0.1.0/24"
register: main_subnetwork
- name: verify create subnetwork
assert:
that:
- main_subnetwork is changed
- main_subnetwork.hcloud_subnetwork.network == "{{ hcloud_network_name }}"
- name: create route
hcloud_route:
network: "{{ hcloud_network_name }}"
destination: "10.0.3.0/24"
gateway: "10.0.2.1"
register: main_route
- name: verify create route
assert:
that:
- main_route is changed
- main_route.hcloud_route.network == "{{ hcloud_network_name }}"
- name: test gather hcloud network info in check mode
hcloud_network_info:
check_mode: yes
register: hcloud_network
- name: verify test gather hcloud network info in check mode
assert:
that:
- hcloud_network.hcloud_network_info | selectattr('name','equalto','{{ hcloud_network_name }}') | list | count >= 1
- name: test gather hcloud network info with correct label selector
hcloud_network_info:
label_selector: "key=value"
register: hcloud_network
- name: verify test gather hcloud network with correct label selector
assert:
that:
- hcloud_network.hcloud_network_info | selectattr('name','equalto','{{ hcloud_network_name }}') | list | count >= 1
- name: test gather hcloud network info with wrong label selector
hcloud_network_info:
label_selector: "key!=value"
register: hcloud_network
- name: verify test gather hcloud network with wrong label selector
assert:
that:
- hcloud_network.hcloud_network_info | list | count == 0
- name: test gather hcloud network info with correct name
hcloud_network_info:
name: "{{hcloud_network_name}}"
register: hcloud_network
- name: verify test gather hcloud network with correct name
assert:
that:
- hcloud_network.hcloud_network_info | selectattr('name','equalto','{{ hcloud_network_name }}') | list | count == 1
- hcloud_network.hcloud_network_info[0].subnetworks | list | count >= 1
- hcloud_network.hcloud_network_info[0].routes | list | count >= 1
- name: test gather hcloud network info with wrong name
hcloud_network_info:
name: "{{hcloud_network_name}}1"
register: hcloud_network
- name: verify test gather hcloud network with wrong name
assert:
that:
- hcloud_network.hcloud_network_info | list | count == 0
- name: test gather hcloud network info with correct id
hcloud_network_info:
id: "{{main_network.hcloud_network.id}}"
register: hcloud_network
- name: verify test gather hcloud network with correct id
assert:
that:
- hcloud_network.hcloud_network_info | selectattr('name','equalto','{{ hcloud_network_name }}') | list | count == 1
- name: test gather hcloud network info with wrong id
hcloud_network_info:
name: "4711"
register: hcloud_network
- name: verify test gather hcloud network with wrong id
assert:
that:
- hcloud_network.hcloud_network_info | list | count == 0
- name: cleanup
hcloud_network:
name: "{{ hcloud_network_name }}"
state: absent

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group1

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_server_name: "{{hcloud_prefix}}-rdns"

@ -1,130 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: cx11
image: "ubuntu-18.04"
ssh_keys:
- ci@ansible.hetzner.cloud
state: present
register: setup
- name: verify setup
assert:
that:
- setup is success
- name: test missing required parameter
hcloud_rdns:
state: present
register: result
ignore_errors: yes
- name: verify fail test missing required parameters
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: ip_address, server" or result.msg == "missing required arguments: server, ip_address"'
- name: test missing required parameters on create
hcloud_rdns:
server: "{{ hcloud_server_name }}"
ip_address: "{{ setup.hcloud_server.ipv6 | ipaddr('next_usable') }}"
state: present
register: result
ignore_errors: yes
- name: verify fail test missing required parameters on create
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: dns_ptr"'
- name: test create rdns with checkmode
hcloud_rdns:
server: "{{ hcloud_server_name }}"
ip_address: "{{ setup.hcloud_server.ipv6 | ipaddr('next_usable') }}"
dns_ptr: "example.com"
state: present
register: result
check_mode: yes
- name: verify test create rdns with checkmode
assert:
that:
- result is changed
- name: test create rdns
hcloud_rdns:
server: "{{ hcloud_server_name }}"
ip_address: "{{ setup.hcloud_server.ipv6 | ipaddr('next_usable') }}"
dns_ptr: "example.com"
state: present
register: rdns
- name: verify create rdns
assert:
that:
- rdns is changed
- rdns.hcloud_rdns.server == "{{ hcloud_server_name }}"
- rdns.hcloud_rdns.ip_address == "{{ setup.hcloud_server.ipv6 | ipaddr('next_usable') }}"
- rdns.hcloud_rdns.dns_ptr == "example.com"
- name: test create rdns idempotency
hcloud_rdns:
server: "{{ hcloud_server_name }}"
ip_address: "{{ setup.hcloud_server.ipv6 | ipaddr('next_usable') }}"
dns_ptr: "example.com"
state: present
register: result
- name: verify create rdns idempotency
assert:
that:
- result is not changed
- name: test absent rdns
hcloud_rdns:
server: "{{ hcloud_server_name }}"
ip_address: "{{ setup.hcloud_server.ipv6 | ipaddr('next_usable') }}"
state: absent
register: result
- name: verify test absent rdns
assert:
that:
- result is changed
- name: test update rdns
hcloud_rdns:
server: "{{ hcloud_server_name }}"
ip_address: "{{ setup.hcloud_server.ipv4_address }}"
dns_ptr: "example.com"
state: present
register: rdns
- name: verify update rdns
assert:
that:
- rdns is changed
- rdns.hcloud_rdns.server == "{{ hcloud_server_name }}"
- rdns.hcloud_rdns.ip_address == "{{ setup.hcloud_server.ipv4_address }}"
- rdns.hcloud_rdns.dns_ptr == "example.com"
- name: test reset rdns
hcloud_rdns:
server: "{{ hcloud_server_name }}"
ip_address: "{{ setup.hcloud_server.ipv4_address }}"
state: present
register: rdns
- name: verify reset rdns
assert:
that:
- rdns is changed
- rdns.hcloud_rdns.server == "{{ hcloud_server_name }}"
- rdns.hcloud_rdns.ip_address == "{{ setup.hcloud_server.ipv4_address }}"
- rdns.hcloud_rdns.dns_ptr != "example.com"
- name: cleanup
hcloud_server:
name: "{{hcloud_server_name}}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group1

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_network_name: "{{hcloud_prefix}}-routes"

@ -1,99 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup
hcloud_network:
name: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/8"
state: present
register: network
- name: verify setup
assert:
that:
- network is success
- name: test missing required parameters on create route
hcloud_route:
state: present
register: result
ignore_errors: yes
- name: verify fail test missing required parameters on create route
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: network, destination, gateway"'
- name: test create route with checkmode
hcloud_route:
network: "{{ hcloud_network_name }}"
destination: "10.100.1.0/24"
gateway: "10.0.1.1"
state: present
register: result
check_mode: yes
- name: verify test create route with checkmode
assert:
that:
- result is changed
- name: test create route
hcloud_route:
network: "{{ hcloud_network_name }}"
destination: "10.100.1.0/24"
gateway: "10.0.1.1"
state: present
register: route
- name: verify create route
assert:
that:
- route is changed
- route.hcloud_route.network == "{{ hcloud_network_name }}"
- route.hcloud_route.destination == "10.100.1.0/24"
- route.hcloud_route.gateway == "10.0.1.1"
- name: test create route idempotency
hcloud_route:
network: "{{ hcloud_network_name }}"
destination: "10.100.1.0/24"
gateway: "10.0.1.1"
state: present
register: result
- name: verify create route idempotency
assert:
that:
- result is not changed
- name: test fail create route with wrong gateway
hcloud_route:
network: "{{ hcloud_network_name }}"
destination: "10.100.1.0/24"
gateway: "10.0.1.2"
state: present
register: route
ignore_errors: yes
- name: verfiy fail create route with wrong gateway
assert:
that:
- route is failed
- name: test absent route
hcloud_route:
network: "{{ hcloud_network_name }}"
destination: "10.100.1.0/24"
gateway: "10.0.1.1"
state: absent
register: result
- name: verify test absent route
assert:
that:
- result is changed
- name: cleanup
hcloud_network:
name: "{{hcloud_network_name}}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group1

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_server_name: "{{hcloud_prefix}}-integration"

@ -1,565 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify setup
assert:
that:
- result is success
- name: test missing required parameters on create server
hcloud_server:
name: "{{ hcloud_server_name }}"
register: result
ignore_errors: yes
- name: verify fail test missing required parameters on create server
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: server_type, image"'
- name: test create server with check mode
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: cx11
image: ubuntu-18.04
state: present
register: result
check_mode: yes
- name: test create server server
assert:
that:
- result is changed
- name: test create server
hcloud_server:
name: "{{ hcloud_server_name}}"
server_type: cx11
image: ubuntu-18.04
state: started
register: main_server
- name: verify create server
assert:
that:
- main_server is changed
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
- main_server.hcloud_server.server_type == "cx11"
- main_server.hcloud_server.status == "running"
- main_server.root_password != ""
- name: test create server idempotence
hcloud_server:
name: "{{ hcloud_server_name }}"
state: started
register: result
- name: verify create server idempotence
assert:
that:
- result is not changed
- name: test stop server with check mode
hcloud_server:
name: "{{ hcloud_server_name }}"
state: stopped
register: result
check_mode: yes
- name: verify stop server with check mode
assert:
that:
- result is changed
- result.hcloud_server.status == "running"
- name: test stop server
hcloud_server:
name: "{{ hcloud_server_name }}"
state: stopped
register: result
- name: verify stop server
assert:
that:
- result is changed
- result.hcloud_server.status == "off"
- name: test start server with check mode
hcloud_server:
name: "{{ hcloud_server_name }}"
state: started
register: result
check_mode: true
- name: verify start server with check mode
assert:
that:
- result is changed
- name: test start server
hcloud_server:
name: "{{ hcloud_server_name }}"
state: started
register: result
- name: verify start server
assert:
that:
- result is changed
- result.hcloud_server.status == "running"
- name: test start server idempotence
hcloud_server:
name: "{{ hcloud_server_name }}"
state: started
register: result
- name: verify start server idempotence
assert:
that:
- result is not changed
- result.hcloud_server.status == "running"
- name: test stop server by its id
hcloud_server:
id: "{{ main_server.hcloud_server.id }}"
state: stopped
register: result
- name: verify stop server by its id
assert:
that:
- result is changed
- result.hcloud_server.status == "off"
- name: test resize server running without force
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: "cx21"
state: present
register: result
check_mode: true
- name: verify test resize server running without force
assert:
that:
- result is changed
- result.hcloud_server.server_type == "cx11"
- name: test resize server with check mode
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: "cx21"
state: stopped
register: result
check_mode: true
- name: verify resize server with check mode
assert:
that:
- result is changed
- name: test resize server without disk
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: "cx21"
state: stopped
register: result
- name: verify resize server without disk
assert:
that:
- result is changed
- result.hcloud_server.server_type == "cx21"
- name: test resize server idempotence
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: "cx21"
state: stopped
register: result
- name: verify resize server idempotence
assert:
that:
- result is not changed
- name: test resize server to smaller plan
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: "cx11"
state: stopped
register: result
- name: verify resize server to smaller plan
assert:
that:
- result is changed
- result.hcloud_server.server_type == "cx11"
- name: test resize server with disk
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: "cx21"
upgrade_disk: true
state: stopped
register: result
- name: verify resize server with disk
assert:
that:
- result is changed
- result.hcloud_server.server_type == "cx21"
- name: test enable backups with check mode
hcloud_server:
name: "{{ hcloud_server_name }}"
backups: true
state: stopped
register: result
check_mode: true
- name: verify enable backups with check mode
assert:
that:
- result is changed
- name: test enable backups
hcloud_server:
name: "{{ hcloud_server_name }}"
backups: true
state: stopped
register: result
- name: verify enable backups
assert:
that:
- result is changed
- result.hcloud_server.backup_window != ""
- name: test enable backups idempotence
hcloud_server:
name: "{{ hcloud_server_name }}"
backups: true
state: stopped
register: result
- name: verify enable backups idempotence
assert:
that:
- result is not changed
- result.hcloud_server.backup_window != ""
- name: test rebuild server
hcloud_server:
name: "{{ hcloud_server_name }}"
image: ubuntu-18.04
state: rebuild
register: result_after_test
- name: verify rebuild server
assert:
that:
- result_after_test is changed
- result.hcloud_server.id == result_after_test.hcloud_server.id
- name: test rebuild server with check mode
hcloud_server:
name: "{{ hcloud_server_name }}"
image: ubuntu-18.04
state: rebuild
register: result_after_test
check_mode: true
- name: verify rebuild server with check mode
assert:
that:
- result_after_test is changed
- name: test update server protection booth protection arguments are required
hcloud_server:
name: "{{ hcloud_server_name }}"
delete_protection: true
state: present
register: result_after_test
ignore_errors: true
- name: verify update server protection booth protection arguments are required
assert:
that:
- result_after_test is failed
- 'result_after_test.msg == "parameters are required together: delete_protection, rebuild_protection"'
- name: test update server protection fails if they are not the same
hcloud_server:
name: "{{ hcloud_server_name }}"
delete_protection: true
rebuild_protection: false
state: present
register: result_after_test
ignore_errors: true
- name: verify update server protection fails if they are not the same
assert:
that:
- result_after_test is failed
- name: test update server protection
hcloud_server:
name: "{{ hcloud_server_name }}"
delete_protection: true
rebuild_protection: true
state: present
register: result_after_test
ignore_errors: true
- name: verify update server protection
assert:
that:
- result_after_test is changed
- result_after_test.hcloud_server.delete_protection is sameas true
- result_after_test.hcloud_server.rebuild_protection is sameas true
- name: test server without protection set to be idempotent
hcloud_server:
name: "{{hcloud_server_name}}"
register: result_after_test
- name: verify test server without protection set to be idempotent
assert:
that:
- result_after_test is not changed
- result_after_test.hcloud_server.delete_protection is sameas true
- result_after_test.hcloud_server.rebuild_protection is sameas true
- name: test delete server fails if it is protected
hcloud_server:
name: "{{hcloud_server_name}}"
state: absent
ignore_errors: yes
register: result
- name: verify delete server fails if it is protected
assert:
that:
- result is failed
- 'result.msg == "server deletion is protected"'
- name: test rebuild server fails if it is protected
hcloud_server:
name: "{{hcloud_server_name}}"
image: ubuntu-18.04
state: rebuild
ignore_errors: yes
register: result
- name: verify rebuild server fails if it is protected
assert:
that:
- result is failed
- 'result.msg == "server rebuild is protected"'
- name: test remove server protection
hcloud_server:
name: "{{ hcloud_server_name }}"
delete_protection: false
rebuild_protection: false
state: present
register: result_after_test
ignore_errors: true
- name: verify remove server protection
assert:
that:
- result_after_test is changed
- result_after_test.hcloud_server.delete_protection is sameas false
- result_after_test.hcloud_server.rebuild_protection is sameas false
- name: absent server
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify absent server
assert:
that:
- result is success
- name: test create server with ssh key
hcloud_server:
name: "{{ hcloud_server_name}}"
server_type: cx11
image: "ubuntu-18.04"
ssh_keys:
- ci@ansible.hetzner.cloud
state: started
register: main_server
- name: verify create server with ssh key
assert:
that:
- main_server is changed
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
- main_server.hcloud_server.server_type == "cx11"
- main_server.hcloud_server.status == "running"
- main_server.root_password != ""
- name: absent server
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify absent server
assert:
that:
- result is success
- name: test create server with rescue_mode
hcloud_server:
name: "{{ hcloud_server_name}}"
server_type: cx11
image: "ubuntu-18.04"
ssh_keys:
- ci@ansible.hetzner.cloud
rescue_mode: "linux64"
state: started
register: main_server
- name: verify create server with rescue_mode
assert:
that:
- main_server is changed
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
- main_server.hcloud_server.server_type == "cx11"
- main_server.hcloud_server.status == "running"
- main_server.root_password != ""
- main_server.hcloud_server.rescue_enabled is sameas true
- name: absent server
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify absent server
assert:
that:
- result is success
- name: setup server
hcloud_server:
name: "{{ hcloud_server_name}}"
server_type: cx11
image: ubuntu-18.04
state: started
register: main_server
- name: verify setup server
assert:
that:
- main_server is changed
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
- main_server.hcloud_server.server_type == "cx11"
- main_server.hcloud_server.status == "running"
- main_server.root_password != ""
- name: test activate rescue mode with check_mode
hcloud_server:
name: "{{ hcloud_server_name }}"
rescue_mode: "linux64"
ssh_keys:
- ci@ansible.hetzner.cloud
state: present
register: main_server
check_mode: true
- name: verify activate rescue mode
assert:
that:
- main_server is changed
- name: test activate rescue mode
hcloud_server:
name: "{{ hcloud_server_name }}"
rescue_mode: "linux64"
ssh_keys:
- ci@ansible.hetzner.cloud
state: present
register: main_server
- name: verify activate rescue mode
assert:
that:
- main_server is changed
- main_server.hcloud_server.rescue_enabled is sameas true
- name: test disable rescue mode
hcloud_server:
name: "{{ hcloud_server_name }}"
ssh_keys:
- ci@ansible.hetzner.cloud
state: present
register: main_server
- name: verify activate rescue mode
assert:
that:
- main_server is changed
- main_server.hcloud_server.rescue_enabled is sameas false
- name: test activate rescue mode without ssh keys
hcloud_server:
name: "{{ hcloud_server_name }}"
rescue_mode: "linux64"
state: present
register: main_server
- name: verify activate rescue mode without ssh keys
assert:
that:
- main_server is changed
- main_server.hcloud_server.rescue_enabled is sameas true
- name: cleanup
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success
- name: test create server with labels
hcloud_server:
name: "{{ hcloud_server_name}}"
server_type: cx11
image: "ubuntu-18.04"
ssh_keys:
- ci@ansible.hetzner.cloud
labels:
key: value
mylabel: "val123"
state: started
register: main_server
- name: verify create server with labels
assert:
that:
- main_server is changed
- main_server.hcloud_server.labels.key == "value"
- main_server.hcloud_server.labels.mylabel == "val123"
- name: test update server with labels
hcloud_server:
name: "{{ hcloud_server_name}}"
server_type: cx11
image: "ubuntu-18.04"
ssh_keys:
- ci@ansible.hetzner.cloud
labels:
key: other
mylabel: "val123"
state: started
register: main_server
- name: verify update server with labels
assert:
that:
- main_server is changed
- main_server.hcloud_server.labels.key == "other"
- main_server.hcloud_server.labels.mylabel == "val123"
- name: test update server with labels in other order
hcloud_server:
name: "{{ hcloud_server_name}}"
server_type: cx11
image: "ubuntu-18.04"
ssh_keys:
- ci@ansible.hetzner.cloud
labels:
mylabel: "val123"
key: other
state: started
register: main_server
- name: verify update server with labels in other order
assert:
that:
- main_server is not changed
- name: cleanup with labels
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_server_name: "{{hcloud_prefix}}-integration"

@ -1,97 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup ensure server is absent
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: create server
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: cx11
image: ubuntu-18.04
state: started
labels:
key: value
register: main_server
- name: verify create server
assert:
that:
- main_server is changed
- main_server.hcloud_server.name == "{{ hcloud_server_name }}"
- main_server.hcloud_server.server_type == "cx11"
- main_server.hcloud_server.status == "running"
- main_server.root_password != ""
- name: test gather hcloud server infos in check mode
hcloud_server_info:
register: hcloud_server
check_mode: yes
- name: verify test gather hcloud server infos in check mode
assert:
that:
- hcloud_server.hcloud_server_info|selectattr('name','equalto','{{ hcloud_server_name }}') | list | count == 1
- name: test gather hcloud server infos with correct label selector
hcloud_server_info:
label_selector: "key=value"
register: hcloud_server
- name: verify test gather hcloud server infos with correct label selector
assert:
that:
- hcloud_server.hcloud_server_info|selectattr('name','equalto','{{ hcloud_server_name }}') | list | count == 1
- name: test gather hcloud server infos with wrong label selector
hcloud_server_info:
label_selector: "key!=value"
register: hcloud_server
- name: verify test gather hcloud server infos with wrong label selector
assert:
that:
- hcloud_server.hcloud_server_info | list | count == 0
- name: test gather hcloud server infos with correct name
hcloud_server_info:
name: "{{hcloud_server_name}}"
register: hcloud_server
- name: verify test gather hcloud server infos with correct name
assert:
that:
- hcloud_server.hcloud_server_info|selectattr('name','equalto','{{ hcloud_server_name }}') | list | count == 1
- name: test gather hcloud server infos with wrong name
hcloud_server_info:
name: "{{hcloud_server_name}}1"
register: hcloud_server
- name: verify test gather hcloud server infos with wrong name
assert:
that:
- hcloud_server.hcloud_server_info | list | count == 0
- name: test gather hcloud server infos with correct id
hcloud_server_info:
id: "{{main_server.hcloud_server.id}}"
register: hcloud_server
- name: verify test gather hcloud server infos with correct id
assert:
that:
- hcloud_server.hcloud_server_info|selectattr('name','equalto','{{ hcloud_server_name }}') | list | count == 1
- name: test gather hcloud server infos with wrong id
hcloud_server_info:
name: "4711"
register: hcloud_server
- name: verify test gather hcloud server infos with wrong id
assert:
that:
- hcloud_server.hcloud_server_info | list | count == 0
- name: cleanup
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,6 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_network_name: "{{hcloud_prefix}}-server-network"
hcloud_server_name: "{{hcloud_prefix}}-server-network"

@ -1,187 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup network
hcloud_network:
name: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/8"
state: present
register: network
- name: verify setup network
assert:
that:
- network is success
- name: setup subnetwork
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/16"
type: "server"
network_zone: "eu-central"
state: present
register: subnetwork
- name: verify subnetwork
assert:
that:
- subnetwork is success
- name: setup server
hcloud_server:
name: "{{hcloud_server_name}}"
server_type: cx11
image: ubuntu-18.04
state: started
location: "fsn1"
register: server
- name: verify setup server
assert:
that:
- server is success
- name: test missing required parameters on create server network
hcloud_server_network:
state: present
register: result
ignore_errors: yes
- name: verify fail test missing required parameters on create server network
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: network, server"'
- name: test create server network with checkmode
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
state: present
register: result
check_mode: yes
- name: verify test create server network with checkmode
assert:
that:
- result is changed
- name: test create server network
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
state: present
register: serverNetwork
- name: verify create server network
assert:
that:
- serverNetwork is changed
- serverNetwork.hcloud_server_network.network == hcloud_network_name
- serverNetwork.hcloud_server_network.server == hcloud_server_name
- name: test create server network idempotency
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
state: present
register: serverNetwork
- name: verify create server network idempotency
assert:
that:
- serverNetwork is not changed
- name: test absent server network
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
state: absent
register: result
- name: verify test absent server network
assert:
that:
- result is changed
- name: test create server network with specified ip
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
ip: "10.0.0.2"
state: present
register: serverNetwork
- name: verify create server network with specified ip
assert:
that:
- serverNetwork is changed
- serverNetwork.hcloud_server_network.network == hcloud_network_name
- serverNetwork.hcloud_server_network.server == hcloud_server_name
- serverNetwork.hcloud_server_network.ip == "10.0.0.2"
- name: cleanup create server network with specified ip
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
state: absent
register: result
- name: verify cleanup create server network with specified ip
assert:
that:
- result is changed
- name: test create server network with alias ips
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
ip: "10.0.0.2"
alias_ips:
- "10.0.1.2"
- "10.0.2.3"
state: present
register: serverNetwork
- name: verify create server network with alias ips
assert:
that:
- serverNetwork is changed
- serverNetwork.hcloud_server_network.network == hcloud_network_name
- serverNetwork.hcloud_server_network.server == hcloud_server_name
- serverNetwork.hcloud_server_network.ip == "10.0.0.2"
- 'serverNetwork.hcloud_server_network.alias_ips[0] == "10.0.2.3"'
- 'serverNetwork.hcloud_server_network.alias_ips[1] == "10.0.1.2"'
- name: cleanup create server network with alias ips
hcloud_server_network:
network: "{{ hcloud_network_name }}"
server: "{{hcloud_server_name}}"
state: absent
register: result
- name: verify cleanup create server network with alias ips
assert:
that:
- result is changed
- name: cleanup server
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify cleanup server
assert:
that:
- result is success
- name: cleanup subnetwork
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/16"
type: "server"
network_zone: "eu-central"
state: absent
register: result
- name: verify cleanup subnetwork
assert:
that:
- result is changed
- name: cleanup
hcloud_network:
name: "{{hcloud_network_name}}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_server_type_name: "cx11"
hcloud_server_type_id: 1

@ -1,38 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: test gather hcloud server type infos
hcloud_server_type_info:
register: hcloud_server_types
- name: verify test gather hcloud server type infos
assert:
that:
- hcloud_server_types.hcloud_server_type_info| list | count > 2
- name: test gather hcloud server type infos in check mode
hcloud_server_type_info:
check_mode: yes
register: hcloud_server_types
- name: verify test gather hcloud server type infos in check mode
assert:
that:
- hcloud_server_types.hcloud_server_type_info| list | count > 2
- name: test gather hcloud server type infos with name
hcloud_server_type_info:
name: "{{hcloud_server_type_name}}"
register: hcloud_server_types
- name: verify test gather hcloud server type with name
assert:
that:
- hcloud_server_types.hcloud_server_type_info|selectattr('name','equalto','{{ hcloud_server_type_name }}') | list | count == 1
- name: test gather hcloud server type infos with correct id
hcloud_server_type_info:
id: "{{hcloud_server_type_id}}"
register: hcloud_server_types
- name: verify test gather hcloud server type with correct id
assert:
that:
- hcloud_server_types.hcloud_server_type_info|selectattr('name','equalto','{{ hcloud_server_type_name }}') | list | count == 1

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,8 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_server_name: "{{hcloud_prefix}}-integration"
hcloud_ssh_key_name: "{{hcloud_prefix}}-integration"
hcloud_ssh_key_public_key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDnaTPfKaX1QKcRLOfr34buVLh5FhJAThI9NYB0xNdXsMd4Y0zLyyCQzHbx4eWCVZxym/s6csWSeLaAhO1GOHeAw3hQFMqf1oTBx6Y8g0pKpeotKPa/PDSUzdZF9Lc+DadtpQd8kFVHAu1Kd3zoEUnk1u6kP7I4qu4Z/6F9qBDF+M3aobiPVxdS7GwaVRW3nZu+FcQDLiBiNOjuRDyjHcDfEUkoh2SOu25RrFtGPzFu5mGmBJwotKpWAocLGfHzyn/fAHxgw3jKZVH/t+XWQFnl82Ie8yE3Z1EZ7oDkNRqFQT9AdXEQOLycTTYTQMJZpgeFTv3sAo6lPRCusiFmmLcf ci@ansible.hetzner.cloud"
hcloud_ssh_key_fingerprint: "56:89:c4:d6:a7:4a:79:82:f4:c2:58:9c:e1:d2:2d:4e"

@ -1,144 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: test missing required parameters on create ssh_key
hcloud_ssh_key:
name: "{{ hcloud_ssh_key_name }}"
register: result
ignore_errors: yes
- name: verify fail test missing required parameters on create ssh_key
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: public_key"'
- name: test create ssh key with check mode
hcloud_ssh_key:
name: "{{ hcloud_ssh_key_name }}"
public_key: "{{ key_material }}"
register: result
check_mode: yes
- name: test create ssh key with check mode
assert:
that:
- result is changed
- name: test create ssh key
hcloud_ssh_key:
name: "{{ hcloud_ssh_key_name }}"
public_key: "{{ key_material }}"
labels:
key: value
my-label: label
register: sshKey
- name: verify create ssh key
assert:
that:
- sshKey is changed
- sshKey.hcloud_ssh_key.name == "{{ hcloud_ssh_key_name }}"
- sshKey.hcloud_ssh_key.public_key == "{{ key_material }}"
- sshKey.hcloud_ssh_key.labels.key == "value"
- name: test create ssh key idempotence
hcloud_ssh_key:
name: "{{ hcloud_ssh_key_name }}"
public_key: "{{ key_material }}"
register: result
- name: verify create ssh key idempotence
assert:
that:
- result is not changed
- name: test update ssh key with check mode
hcloud_ssh_key:
id: "{{ sshKey.hcloud_ssh_key.id }}"
name: "changed-{{ hcloud_ssh_key_name }}"
register: result
check_mode: yes
- name: test create ssh key with check mode
assert:
that:
- result is changed
- name: test update ssh key
hcloud_ssh_key:
id: "{{ sshKey.hcloud_ssh_key.id }}"
name: "changed-{{ hcloud_ssh_key_name }}"
labels:
key: value
register: result
- name: test update ssh key
assert:
that:
- result is changed
- result.hcloud_ssh_key.name == "changed-{{ hcloud_ssh_key_name }}"
- name: test update ssh key with same labels
hcloud_ssh_key:
id: "{{ sshKey.hcloud_ssh_key.id }}"
name: "changed-{{ hcloud_ssh_key_name }}"
labels:
key: value
register: result
- name: test update ssh key with same labels
assert:
that:
- result is not changed
- name: test update ssh key with other labels
hcloud_ssh_key:
id: "{{ sshKey.hcloud_ssh_key.id }}"
name: "changed-{{ hcloud_ssh_key_name }}"
labels:
key: value
test: "val123"
register: result
- name: test update ssh key with other labels
assert:
that:
- result is changed
- name: test rename ssh key
hcloud_ssh_key:
id: "{{ sshKey.hcloud_ssh_key.id }}"
name: "{{ hcloud_ssh_key_name }}"
register: result
- name: test rename ssh key
assert:
that:
- result is changed
- result.hcloud_ssh_key.name == "{{ hcloud_ssh_key_name }}"
- name: test create server with ssh key
hcloud_server:
name: "{{ hcloud_server_name }}"
server_type: cx11
image: "ubuntu-18.04"
ssh_keys:
- "{{ hcloud_ssh_key_name }}"
state: started
register: main_server
- name: verify create server with ssh key
assert:
that:
- main_server is changed
- name: absent ssh key
hcloud_ssh_key:
id: "{{ sshKey.hcloud_ssh_key.id }}"
state: absent
register: result
- name: verify absent server
assert:
that:
- result is success
- name: cleanup
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_ssh_key_name: "{{hcloud_prefix}}-ssh_key_facts"

@ -1,68 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup ensure ssh key is absent
hcloud_ssh_key:
name: "{{ hcloud_ssh_key_name }}"
state: absent
register: result
- name: setup test ssh_key
hcloud_ssh_key:
name: "{{hcloud_ssh_key_name}}"
public_key: "{{ key_material }}"
labels:
key: value
register: result
- name: verify create test ssh_key
assert:
that:
- result is changed
- result.hcloud_ssh_key.public_key == "{{ key_material }}"
- name: test gather hcloud ssh key infos in check mode
hcloud_ssh_key_info:
register: hcloud_ssh_key
check_mode: yes
- name: verify test gather hcloud ssh key infos in check mode
assert:
that:
- hcloud_ssh_key.hcloud_ssh_key_info| list | count >= 1
- name: test gather hcloud ssh key infos
hcloud_ssh_key_info:
register: hcloud_ssh_key
check_mode: yes
- name: verify test gather hcloud ssh key infos
assert:
that:
- hcloud_ssh_key.hcloud_ssh_key_info| list | count >= 1
- name: test gather hcloud ssh key infos with correct label selector
hcloud_ssh_key_info:
label_selector: "key=value"
register: hcloud_ssh_key
- name: verify test gather hcloud ssh key infos with correct label selector
assert:
that:
- hcloud_ssh_key.hcloud_ssh_key_info|selectattr('name','equalto','{{ hcloud_ssh_key_name }}') | list | count == 1
- name: test gather hcloud ssh key infos with wrong label selector
hcloud_ssh_key_info:
label_selector: "key!=value"
register: hcloud_ssh_key
- name: verify test gather hcloud ssh key infos with wrong label selector
assert:
that:
- hcloud_ssh_key.hcloud_ssh_key_info | list | count == 0
- name: cleanup
hcloud_ssh_key:
name: "{{hcloud_ssh_key_name}}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_network_name: "{{hcloud_prefix}}-subnet"

@ -1,92 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup
hcloud_network:
name: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/8"
state: present
register: network
- name: verify setup
assert:
that:
- network is success
- name: test missing required parameters on create route
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
state: present
register: result
ignore_errors: yes
- name: verify fail test missing required parameters on create route
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: network_zone, type, ip_range"'
- name: test create subnetwork with checkmode
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/16"
type: "server"
network_zone: "eu-central"
state: present
register: result
check_mode: yes
- name: verify test create subnetwork with checkmode
assert:
that:
- result is changed
- name: test create subnetwork
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/16"
type: "server"
network_zone: "eu-central"
state: present
register: subnet
- name: verify create subnetwork
assert:
that:
- subnet is changed
- subnet.hcloud_subnetwork.network == "{{ hcloud_network_name }}"
- subnet.hcloud_subnetwork.ip_range == "10.0.0.0/16"
- subnet.hcloud_subnetwork.type == "server"
- subnet.hcloud_subnetwork.network_zone == "eu-central"
- name: test create subnetwork idempotency
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/16"
type: "server"
network_zone: "eu-central"
state: present
register: result
- name: verify create subnetwork idempotency
assert:
that:
- result is not changed
- name: test absent subnetwork
hcloud_subnetwork:
network: "{{ hcloud_network_name }}"
ip_range: "10.0.0.0/16"
type: "server"
network_zone: "eu-central"
state: absent
register: result
- name: verify test absent subnetwork
assert:
that:
- result is changed
- name: cleanup
hcloud_network:
name: "{{hcloud_network_name}}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,6 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_volume_name: "{{hcloud_prefix}}-integ"
hcloud_server_name: "{{hcloud_prefix}}-volume-server"

@ -1,242 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup server
hcloud_server:
name: "{{hcloud_server_name}}"
server_type: cx11
image: ubuntu-18.04
state: started
location: "fsn1"
register: vol_server
- name: verify setup server
assert:
that:
- vol_server is changed
- name: test missing size parameter on create Volume
hcloud_volume:
name: "{{hcloud_volume_name}}"
server: "{{hcloud_server_name}}"
register: result
ignore_errors: yes
- name: verify fail test missing size parameter on create Volume
assert:
that:
- result is failed
- 'result.msg == "missing required arguments: size"'
- name: test create Volume with check mode
hcloud_volume:
name: "{{hcloud_volume_name}}"
size: 10
location: "fsn1"
register: result
check_mode: yes
- name: verify create Volume with check mode result
assert:
that:
- result is changed
- name: test create Volume
hcloud_volume:
name: "{{hcloud_volume_name}}"
size: 10
location: "fsn1"
register: volume
- name: verify test create Volume
assert:
that:
- volume is changed
- volume.hcloud_volume.name == "{{hcloud_volume_name}}"
- volume.hcloud_volume.location == "fsn1"
- volume.hcloud_volume.size == 10
- volume.hcloud_volume.server != "{{hcloud_server_name}}"
- volume.hcloud_volume.linux_device is defined
- name: test create Volume idempotence
hcloud_volume:
name: "{{hcloud_volume_name}}"
size: 10
location: "fsn1"
register: volume
- name: verify test create Volume
assert:
that:
- volume is not changed
- name: test attach Volume with checkmode
hcloud_volume:
name: "{{hcloud_volume_name}}"
server: "{{hcloud_server_name}}"
check_mode: yes
register: volume
- name: verify test attach Volume with checkmode
assert:
that:
- volume is changed
- volume.hcloud_volume.server != "{{hcloud_server_name}}"
- name: test attach Volume
hcloud_volume:
name: "{{hcloud_volume_name}}"
server: "{{hcloud_server_name}}"
register: volume
- name: verify attach volume
assert:
that:
- volume is changed
- volume.hcloud_volume.server == "{{hcloud_server_name}}"
- name: test attach Volume idempotence
hcloud_volume:
name: "{{hcloud_volume_name}}"
server: "{{hcloud_server_name}}"
register: volume
- name: verify attach Volume idempotence
assert:
that:
- volume is not changed
- volume.hcloud_volume.server == "{{hcloud_server_name}}"
- name: test detach Volume with checkmode
hcloud_volume:
name: "{{hcloud_volume_name}}"
check_mode: yes
register: volume
- name: verify detach Volume with checkmode
assert:
that:
- volume is changed
- volume.hcloud_volume.server == "{{hcloud_server_name}}"
- name: test detach Volume
hcloud_volume:
name: "{{hcloud_volume_name}}"
register: volume
- name: verify detach volume
assert:
that:
- volume is changed
- volume.hcloud_volume.location == "fsn1"
- volume.hcloud_volume.server != "{{hcloud_server_name}}"
- name: test update Volume label
hcloud_volume:
name: "{{hcloud_volume_name}}"
labels:
key: value
register: volume
- name: verify test update Volume label
assert:
that:
- volume is changed
- volume.hcloud_volume.labels.key == "value"
- name: test update Volume label with the same label
hcloud_volume:
name: "{{hcloud_volume_name}}"
labels:
key: value
register: volume
- name: verify test update Volume lable with the same label
assert:
that:
- volume is not changed
- name: test increase Volume size
hcloud_volume:
name: "{{hcloud_volume_name}}"
size: 11
register: volume
- name: verify test increase Volume size
assert:
that:
- volume is changed
- volume.hcloud_volume.size == 11
- name: test decreace Volume size
hcloud_volume:
name: "{{hcloud_volume_name}}"
size: 10
register: volume
- name: verify test decreace Volume size
assert:
that:
- volume is not changed
- volume.hcloud_volume.size == 11
- name: test update Volume delete protection
hcloud_volume:
name: "{{hcloud_volume_name}}"
delete_protection: true
register: volume
- name: verify test update Volume delete protection
assert:
that:
- volume is changed
- volume.hcloud_volume.delete_protection is sameas true
- name: test update Volume delete protection idempotency
hcloud_volume:
name: "{{hcloud_volume_name}}"
delete_protection: true
register: volume
- name: verify test update Volume delete protection idempotency
assert:
that:
- volume is not changed
- volume.hcloud_volume.delete_protection is sameas true
- name: test Volume without delete protection set to be idempotent
hcloud_volume:
name: "{{hcloud_volume_name}}"
register: volume
- name: verify test Volume without delete protection set to be idempotent
assert:
that:
- volume is not changed
- volume.hcloud_volume.delete_protection is sameas true
- name: test delete Volume fails if it is protected
hcloud_volume:
name: "{{hcloud_volume_name}}"
state: absent
ignore_errors: yes
register: result
- name: verify delete Volume fails if it is protected
assert:
that:
- result is failed
- 'result.msg == "volume deletion is protected"'
- name: test update Volume delete protection
hcloud_volume:
name: "{{hcloud_volume_name}}"
delete_protection: false
register: volume
- name: verify test update Volume delete protection
assert:
that:
- volume is changed
- volume.hcloud_volume.delete_protection is sameas false
- name: test delete Volume
hcloud_volume:
name: "{{hcloud_volume_name}}"
state: absent
register: result
- name: verify delete Volume
assert:
that:
- result is success
- name: cleanup
hcloud_server:
name: "{{ hcloud_server_name }}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1,2 +0,0 @@
cloud/hcloud
shippable/hcloud/group2

@ -1,5 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
hcloud_prefix: "tests"
hcloud_volume_name: "{{hcloud_prefix}}-facts"

@ -1,101 +0,0 @@
# Copyright: (c) 2019, Hetzner Cloud GmbH <info@hetzner-cloud.de>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
---
- name: setup ensure volume is absent
hcloud_volume:
name: "{{ hcloud_volume_name }}"
state: absent
register: result
- name: setup volume
hcloud_volume:
name: "{{hcloud_volume_name}}"
size: 10
location: "fsn1"
labels:
key: value
register: main_volume
- name: verify setup volume
assert:
that:
- main_volume is changed
- name: test gather hcloud volume infos in check mode
hcloud_volume_info:
register: hcloud_volume
check_mode: yes
- name: verify test gather hcloud volume infos in check mode
vars:
volume: "{{ hcloud_volume.hcloud_volume_info|selectattr('name','equalto',hcloud_volume_name) | first }}"
assert:
that:
- hcloud_volume.hcloud_volume_info|selectattr('name','equalto','{{ hcloud_volume_name }}') | list | count == 1
- volume.name == "{{hcloud_volume_name}}"
- volume.location == "fsn1"
- volume.size == 10
- volume.linux_device is defined
- name: test gather hcloud volume infos with correct label selector
hcloud_volume_info:
label_selector: "key=value"
register: hcloud_volume
- name: verify test gather hcloud volume infos with correct label selector
assert:
that:
- hcloud_volume.hcloud_volume_info|selectattr('name','equalto','{{ hcloud_volume_name }}') | list | count == 1
- name: test gather hcloud volume infos with wrong label selector
hcloud_volume_info:
label_selector: "key!=value"
register: hcloud_volume
- name: verify test gather hcloud volume infos with wrong label selector
assert:
that:
- hcloud_volume.hcloud_volume_info | list | count == 0
- name: test gather hcloud volume infos with correct name
hcloud_volume_info:
name: "{{hcloud_volume_name}}"
register: hcloud_volume
- name: verify test gather hcloud volume infos with correct name
assert:
that:
- hcloud_volume.hcloud_volume_info|selectattr('name','equalto','{{ hcloud_volume_name }}') | list | count == 1
- name: test gather hcloud volume infos with wrong name
hcloud_volume_info:
name: "{{hcloud_volume_name}}1"
register: hcloud_volume
- name: verify test gather hcloud volume infos with wrong name
assert:
that:
- hcloud_volume.hcloud_volume_info | list | count == 0
- name: test gather hcloud volume facts with correct id
hcloud_volume_info:
id: "{{main_volume.hcloud_volume.id}}"
register: hcloud_volume
- name: verify test gather hcloud volume with correct id
assert:
that:
- hcloud_volume.hcloud_volume_info|selectattr('name','equalto','{{ hcloud_volume_name }}') | list | count == 1
- name: test gather hcloud volume infos with wrong id
hcloud_volume_info:
name: "4711"
register: hcloud_volume
- name: verify test gather hcloud volume infos with wrong id
assert:
that:
- hcloud_volume.hcloud_volume_info | list | count == 0
- name: cleanup
hcloud_volume:
name: "{{ hcloud_volume_name }}"
state: absent
register: result
- name: verify cleanup
assert:
that:
- result is success

@ -1005,9 +1005,6 @@ lib/ansible/modules/cloud/google/gcp_storage_bucket_access_control.py validate-m
lib/ansible/modules/cloud/google/gcp_storage_object.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/google/gcp_tpu_node.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/google/gcp_tpu_node_info.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/hcloud/hcloud_network_info.py validate-modules:return-syntax-error
lib/ansible/modules/cloud/hcloud/hcloud_server.py validate-modules:parameter-list-no-elements
lib/ansible/modules/cloud/hcloud/hcloud_server_network.py validate-modules:parameter-list-no-elements
lib/ansible/modules/commands/command.py validate-modules:doc-missing-type
lib/ansible/modules/commands/command.py validate-modules:nonexistent-parameter-documented
lib/ansible/modules/commands/command.py validate-modules:parameter-list-no-elements
@ -1342,8 +1339,6 @@ lib/ansible/plugins/doc_fragments/default_callback.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/default_callback.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/files.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/files.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/hcloud.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/hcloud.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/inventory_cache.py future-import-boilerplate
lib/ansible/plugins/doc_fragments/inventory_cache.py metaclass-boilerplate
lib/ansible/plugins/doc_fragments/return_common.py future-import-boilerplate

Loading…
Cancel
Save