mirror of
https://github.com/ansible-collections/hetzner.hcloud.git
synced 2026-02-03 23:51:48 +00:00
feat: add support for Storage Boxes (#676)
##### SUMMARY We collect all changes for the Storage Box support in this PR. It will only be merged when everything is implemented through smaller pull requests targeting the `storage-boxes` branch. --------- Co-authored-by: Julian Tölle <julian.toelle@hetzner-cloud.de>
This commit is contained in:
parent
bc61715c92
commit
5394c6f246
109 changed files with 4305 additions and 4 deletions
52
changelogs/fragments/storage-boxes.yml
Normal file
52
changelogs/fragments/storage-boxes.yml
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
minor_changes:
|
||||||
|
- storage_box - New module to create and manage Storage Boxes in Hetzner.
|
||||||
|
- storage_box_info - New module to gather infos about Hetzner Storage Boxes.
|
||||||
|
- storage_box_snapshot - New module to create and manage Storage Box Snapshots in Hetzner.
|
||||||
|
- storage_box_snapshot_info - New module to gather infos about Hetzner Storage Box Snapshots.
|
||||||
|
- storage_box_subaccount - New module to create and manage Storage Box Subaccounts in Hetzner.
|
||||||
|
- storage_box_subaccount_info - New module to gather infos about Hetzner Storage Box Subaccounts.
|
||||||
|
- storage_box_type_info - New module to gather infos about Hetzner Storage Box Types.
|
||||||
|
release_summary: |
|
||||||
|
This release adds support for the new `Storage Box API`_.
|
||||||
|
|
||||||
|
Storage Box support is **experimental**, breaking changes may occur within minor releases.
|
||||||
|
|
||||||
|
See the `experimental tracking issue`_ for more details.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
.. code:: yaml
|
||||||
|
|
||||||
|
- name: Create a Storage Box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: backups
|
||||||
|
storage_box_type: bx11
|
||||||
|
location: fsn1
|
||||||
|
password: my-secret
|
||||||
|
access_settings:
|
||||||
|
reachable_externally: true
|
||||||
|
ssh_enabled: true
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create a Storage Box Subaccount
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: backups
|
||||||
|
name: subaccount1
|
||||||
|
home_directory: backups/subaccount1
|
||||||
|
password: secret
|
||||||
|
access_settings:
|
||||||
|
readonly: true
|
||||||
|
labels:
|
||||||
|
env: prod
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Take a Storage Box Snapshot
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: backups
|
||||||
|
description: before app migration
|
||||||
|
labels:
|
||||||
|
env: prod
|
||||||
|
state: present
|
||||||
|
|
||||||
|
.. _Storage Box API: https://docs.hetzner.cloud/reference/hetzner#storage-boxes
|
||||||
|
.. _experimental tracking issue: https://github.com/ansible-collections/hetzner.hcloud/issues/756
|
||||||
|
|
@ -32,6 +32,13 @@ action_groups:
|
||||||
- server_type_info
|
- server_type_info
|
||||||
- ssh_key
|
- ssh_key
|
||||||
- ssh_key_info
|
- ssh_key_info
|
||||||
|
- storage_box
|
||||||
|
- storage_box_info
|
||||||
|
- storage_box_snapshot
|
||||||
|
- storage_box_snapshot_info
|
||||||
|
- storage_box_subaccount
|
||||||
|
- storage_box_subaccount_info
|
||||||
|
- storage_box_type_info
|
||||||
- subnetwork
|
- subnetwork
|
||||||
- volume
|
- volume
|
||||||
- volume_info
|
- volume_info
|
||||||
|
|
@ -103,6 +110,20 @@ plugin_routing:
|
||||||
redirect: hetzner.hcloud.ssh_key_info
|
redirect: hetzner.hcloud.ssh_key_info
|
||||||
hcloud_ssh_key:
|
hcloud_ssh_key:
|
||||||
redirect: hetzner.hcloud.ssh_key
|
redirect: hetzner.hcloud.ssh_key
|
||||||
|
hcloud_storage_box:
|
||||||
|
redirect: storage_box
|
||||||
|
hcloud_storage_box_info:
|
||||||
|
redirect: storage_box_info
|
||||||
|
hcloud_storage_box_snapshot:
|
||||||
|
redirect: storage_box_snapshot
|
||||||
|
hcloud_storage_box_snapshot_info:
|
||||||
|
redirect: storage_box_snapshot_info
|
||||||
|
hcloud_storage_box_subaccount:
|
||||||
|
redirect: storage_box_subaccount
|
||||||
|
hcloud_storage_box_subaccount_info:
|
||||||
|
redirect: storage_box_subaccount_info
|
||||||
|
hcloud_storage_box_type_info:
|
||||||
|
redirect: storage_box_type_info
|
||||||
hcloud_subnetwork:
|
hcloud_subnetwork:
|
||||||
redirect: hetzner.hcloud.subnetwork
|
redirect: hetzner.hcloud.subnetwork
|
||||||
hcloud_volume_info:
|
hcloud_volume_info:
|
||||||
|
|
|
||||||
|
|
@ -10,24 +10,30 @@ class ModuleDocFragment:
|
||||||
options:
|
options:
|
||||||
api_token:
|
api_token:
|
||||||
description:
|
description:
|
||||||
- The API Token for the Hetzner Cloud.
|
- The token for the Hetzner Cloud API.
|
||||||
- You can also set this option by using the C(HCLOUD_TOKEN) environment variable.
|
- You can also set this option by using the C(HCLOUD_TOKEN) environment variable.
|
||||||
required: True
|
required: True
|
||||||
type: str
|
type: str
|
||||||
api_endpoint:
|
api_endpoint:
|
||||||
description:
|
description:
|
||||||
- The API Endpoint for the Hetzner Cloud.
|
- The endpoint for the Hetzner Cloud API.
|
||||||
- You can also set this option by using the C(HCLOUD_ENDPOINT) environment variable.
|
- You can also set this option by using the C(HCLOUD_ENDPOINT) environment variable.
|
||||||
default: https://api.hetzner.cloud/v1
|
default: https://api.hetzner.cloud/v1
|
||||||
type: str
|
type: str
|
||||||
aliases: [endpoint]
|
aliases: [endpoint]
|
||||||
|
api_endpoint_hetzner:
|
||||||
|
description:
|
||||||
|
- The endpoint for the Hetzner API.
|
||||||
|
- You can also set this option by using the C(HETZNER_ENDPOINT) environment variable.
|
||||||
|
default: https://api.hetzner.com/v1
|
||||||
|
type: str
|
||||||
|
|
||||||
requirements:
|
requirements:
|
||||||
- python-dateutil >= 2.7.5
|
- python-dateutil >= 2.7.5
|
||||||
- requests >=2.20
|
- requests >=2.20
|
||||||
|
|
||||||
seealso:
|
seealso:
|
||||||
- name: Documentation for Hetzner Cloud API
|
- name: Documentation for Hetzner APIs
|
||||||
description: Complete reference for the Hetzner Cloud API.
|
description: Complete reference for the Hetzner APIs.
|
||||||
link: https://docs.hetzner.cloud
|
link: https://docs.hetzner.cloud
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -32,3 +32,10 @@ def experimental_warning_function(product: str, maturity: str, url: str):
|
||||||
module.warn(message)
|
module.warn(message)
|
||||||
|
|
||||||
return fn
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
storage_box_experimental_warning = experimental_warning_function(
|
||||||
|
"Storage Box support",
|
||||||
|
"experimental",
|
||||||
|
"https://github.com/ansible-collections/hetzner.hcloud/issues/756",
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ class AnsibleHCloud:
|
||||||
self.client = Client(
|
self.client = Client(
|
||||||
token=self.module.params["api_token"],
|
token=self.module.params["api_token"],
|
||||||
api_endpoint=self.module.params["api_endpoint"],
|
api_endpoint=self.module.params["api_endpoint"],
|
||||||
|
api_endpoint_hetzner=self.module.params["api_endpoint_hetzner"],
|
||||||
application_name="ansible-module",
|
application_name="ansible-module",
|
||||||
application_version=version,
|
application_version=version,
|
||||||
# Total waiting time before timeout is > 117.0
|
# Total waiting time before timeout is > 117.0
|
||||||
|
|
@ -163,6 +164,11 @@ class AnsibleHCloud:
|
||||||
"default": "https://api.hetzner.cloud/v1",
|
"default": "https://api.hetzner.cloud/v1",
|
||||||
"aliases": ["endpoint"],
|
"aliases": ["endpoint"],
|
||||||
},
|
},
|
||||||
|
"api_endpoint_hetzner": {
|
||||||
|
"type": "str",
|
||||||
|
"fallback": (env_fallback, ["HETZNER_ENDPOINT"]),
|
||||||
|
"default": "https://api.hetzner.com/v1",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def _prepare_result(self) -> dict[str, Any]:
|
def _prepare_result(self) -> dict[str, Any]:
|
||||||
|
|
|
||||||
66
plugins/module_utils/storage_box.py
Normal file
66
plugins/module_utils/storage_box.py
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from ..module_utils.client import client_resource_not_found
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
StorageBoxesClient,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get(client: StorageBoxesClient, param: str | int) -> BoundStorageBox:
|
||||||
|
"""
|
||||||
|
Get a Bound Storage Box either by ID or name.
|
||||||
|
|
||||||
|
If the given parameter is an ID, return a partial Bound Storage Box to reduce the amount
|
||||||
|
of API requests.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return BoundStorageBox(
|
||||||
|
client,
|
||||||
|
data={"id": int(param)},
|
||||||
|
complete=False,
|
||||||
|
)
|
||||||
|
except ValueError: # param is not an id
|
||||||
|
result = client.get_by_name(param)
|
||||||
|
if result is None:
|
||||||
|
# pylint: disable=raise-missing-from
|
||||||
|
raise client_resource_not_found("storage box", param)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_result(o: BoundStorageBox):
|
||||||
|
return {
|
||||||
|
"id": o.id,
|
||||||
|
"name": o.name,
|
||||||
|
"storage_box_type": o.storage_box_type.name,
|
||||||
|
"location": o.location.name,
|
||||||
|
"labels": o.labels,
|
||||||
|
"delete_protection": o.protection["delete"],
|
||||||
|
"access_settings": {
|
||||||
|
"reachable_externally": o.access_settings.reachable_externally,
|
||||||
|
"samba_enabled": o.access_settings.samba_enabled,
|
||||||
|
"ssh_enabled": o.access_settings.ssh_enabled,
|
||||||
|
"webdav_enabled": o.access_settings.webdav_enabled,
|
||||||
|
"zfs_enabled": o.access_settings.zfs_enabled,
|
||||||
|
},
|
||||||
|
"username": o.username,
|
||||||
|
"server": o.server,
|
||||||
|
"system": o.system,
|
||||||
|
"status": o.status,
|
||||||
|
"stats": {
|
||||||
|
"size": o.stats.size,
|
||||||
|
"size_data": o.stats.size_data,
|
||||||
|
"size_snapshots": o.stats.size_snapshots,
|
||||||
|
},
|
||||||
|
"snapshot_plan": (
|
||||||
|
None
|
||||||
|
if o.snapshot_plan is None
|
||||||
|
else {
|
||||||
|
"max_snapshots": o.snapshot_plan.max_snapshots,
|
||||||
|
"hour": o.snapshot_plan.hour,
|
||||||
|
"minute": o.snapshot_plan.minute,
|
||||||
|
"day_of_week": o.snapshot_plan.day_of_week,
|
||||||
|
"day_of_month": o.snapshot_plan.day_of_month,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
21
plugins/module_utils/storage_box_snapshot.py
Normal file
21
plugins/module_utils/storage_box_snapshot.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBoxSnapshot,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_result(o: BoundStorageBoxSnapshot):
|
||||||
|
return {
|
||||||
|
"storage_box": o.storage_box.id,
|
||||||
|
"id": o.id,
|
||||||
|
"name": o.name,
|
||||||
|
"description": o.description,
|
||||||
|
"labels": o.labels,
|
||||||
|
"stats": {
|
||||||
|
"size": o.stats.size,
|
||||||
|
"size_filesystem": o.stats.size_filesystem,
|
||||||
|
},
|
||||||
|
"is_automatic": o.is_automatic,
|
||||||
|
"created": o.created.isoformat(),
|
||||||
|
}
|
||||||
44
plugins/module_utils/storage_box_subaccount.py
Normal file
44
plugins/module_utils/storage_box_subaccount.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
BoundStorageBoxSubaccount,
|
||||||
|
)
|
||||||
|
|
||||||
|
NAME_LABEL_KEY = "ansible-name"
|
||||||
|
|
||||||
|
|
||||||
|
def get_by_name(storage_box: BoundStorageBox, name: str):
|
||||||
|
if not name:
|
||||||
|
raise ValueError(f"invalid storage box subaccount name: '{name}'")
|
||||||
|
|
||||||
|
result = storage_box.get_subaccount_list(
|
||||||
|
label_selector=f"{NAME_LABEL_KEY}={name}",
|
||||||
|
)
|
||||||
|
if len(result.subaccounts) == 0:
|
||||||
|
return None
|
||||||
|
if len(result.subaccounts) == 1:
|
||||||
|
return result.subaccounts[0]
|
||||||
|
|
||||||
|
raise ValueError(f"found multiple storage box subaccount with the same name: {name}")
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_result(o: BoundStorageBoxSubaccount, name: str):
|
||||||
|
return {
|
||||||
|
"storage_box": o.storage_box.id,
|
||||||
|
"id": o.id,
|
||||||
|
"name": name,
|
||||||
|
"description": o.description,
|
||||||
|
"username": o.username,
|
||||||
|
"home_directory": o.home_directory,
|
||||||
|
"server": o.server,
|
||||||
|
"access_settings": {
|
||||||
|
"reachable_externally": o.access_settings.reachable_externally,
|
||||||
|
"samba_enabled": o.access_settings.samba_enabled,
|
||||||
|
"ssh_enabled": o.access_settings.ssh_enabled,
|
||||||
|
"webdav_enabled": o.access_settings.webdav_enabled,
|
||||||
|
"readonly": o.access_settings.readonly,
|
||||||
|
},
|
||||||
|
"labels": o.labels,
|
||||||
|
"created": o.created.isoformat(),
|
||||||
|
}
|
||||||
623
plugins/modules/storage_box.py
Normal file
623
plugins/modules/storage_box.py
Normal file
|
|
@ -0,0 +1,623 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2025, 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 annotations
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: storage_box
|
||||||
|
|
||||||
|
short_description: Create and manage Storage Boxes in Hetzner.
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Create, update and delete Storage Boxes in Hetzner.
|
||||||
|
- See the L(Storage Boxes API documentation,https://docs.hetzner.cloud/reference/hetzner#storage-boxes) for more details.
|
||||||
|
- B(Experimental:) Storage Box support is experimental, breaking changes may occur within minor releases.
|
||||||
|
See https://github.com/ansible-collections/hetzner.hcloud/issues/756 for more details.
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Jonas Lammler (@jooola)
|
||||||
|
|
||||||
|
options:
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- ID of the Storage Box to manage.
|
||||||
|
- Required if no Storage Box O(name) is given.
|
||||||
|
- If the ID is invalid, the module will fail.
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the Storage Box to manage.
|
||||||
|
- Required if no Storage Box O(id) is given.
|
||||||
|
- Required if the Storage Box does not exist.
|
||||||
|
type: str
|
||||||
|
storage_box_type:
|
||||||
|
description:
|
||||||
|
- Name or ID of the Storage Box Type for the Storage Box.
|
||||||
|
- Required if the Storage Box does not exist.
|
||||||
|
type: str
|
||||||
|
aliases: [type]
|
||||||
|
location:
|
||||||
|
description:
|
||||||
|
- Name or ID of the Location for the Storage Box.
|
||||||
|
- Required if the Storage Box does not exist.
|
||||||
|
type: str
|
||||||
|
password:
|
||||||
|
description:
|
||||||
|
- Password for the Storage Box.
|
||||||
|
- Required if the Storage Box does not exist.
|
||||||
|
type: str
|
||||||
|
labels:
|
||||||
|
description:
|
||||||
|
- User-defined labels (key-value pairs) for the Storage Box.
|
||||||
|
type: dict
|
||||||
|
ssh_keys:
|
||||||
|
description:
|
||||||
|
- SSH public keys in OpenSSH format to inject into the Storage Box.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
access_settings:
|
||||||
|
description:
|
||||||
|
- Access settings of the Storage Box.
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
reachable_externally:
|
||||||
|
description:
|
||||||
|
- Whether access from outside the Hetzner network is allowed.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
samba_enabled:
|
||||||
|
description:
|
||||||
|
- Whether the Samba subsystem is enabled.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
ssh_enabled:
|
||||||
|
description:
|
||||||
|
- Whether the SSH subsystem is enabled.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
webdav_enabled:
|
||||||
|
description:
|
||||||
|
- Whether the WebDAV subsystem is enabled.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
zfs_enabled:
|
||||||
|
description:
|
||||||
|
- Whether the ZFS snapshot folder is visible.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
snapshot_plan:
|
||||||
|
description:
|
||||||
|
- Snapshot plan of the Storage Box.
|
||||||
|
- Use null to disabled the snapshot plan.
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
max_snapshots:
|
||||||
|
description:
|
||||||
|
- Maximum amount of Snapshots that will be created by this Snapshot Plan.
|
||||||
|
- Older Snapshots will be deleted.
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
hour:
|
||||||
|
description:
|
||||||
|
- Hour when the Snapshot Plan is executed (UTC).
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
minute:
|
||||||
|
description:
|
||||||
|
- Minute when the Snapshot Plan is executed (UTC).
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
day_of_week:
|
||||||
|
description:
|
||||||
|
- Day of the week when the Snapshot Plan is executed.
|
||||||
|
- Starts at 1 for Monday til 7 for Sunday.
|
||||||
|
- Null means every day.
|
||||||
|
type: int
|
||||||
|
day_of_month:
|
||||||
|
description:
|
||||||
|
- Day of the month when the Snapshot Plan is executed.
|
||||||
|
- Null means every day.
|
||||||
|
type: int
|
||||||
|
delete_protection:
|
||||||
|
description:
|
||||||
|
- Protect the Storage Box from deletion.
|
||||||
|
type: bool
|
||||||
|
snapshot:
|
||||||
|
description:
|
||||||
|
- Snapshot ID or Name to rollback to.
|
||||||
|
- Only used when O(state=rollback_snapshot)
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- State of the Storage Box.
|
||||||
|
- C(reset_password) and C(rollback_snapshot) are not idempotent.
|
||||||
|
default: present
|
||||||
|
choices: [absent, present, reset_password, rollback_snapshot]
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- hetzner.hcloud.hcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Create a Storage Box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: my-storage-box
|
||||||
|
storage_box_type: bx11
|
||||||
|
location: fsn1
|
||||||
|
password: my-secret
|
||||||
|
labels:
|
||||||
|
env: prod
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create a Storage Box with access settings
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: my-storage-box
|
||||||
|
storage_box_type: bx11
|
||||||
|
location: fsn1
|
||||||
|
password: my-secret
|
||||||
|
access_settings:
|
||||||
|
reachable_externally: true
|
||||||
|
ssh_enabled: true
|
||||||
|
samba_enabled: false
|
||||||
|
webdav_enabled: false
|
||||||
|
zfs_enabled: false
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Create a Storage Box with snapshot plan
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: my-storage-box
|
||||||
|
storage_box_type: bx11
|
||||||
|
location: fsn1
|
||||||
|
password: my-secret
|
||||||
|
snapshot_plan:
|
||||||
|
max_snapshots: 10
|
||||||
|
hour: 3
|
||||||
|
minute: 30
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Disable a Storage Box snapshot plan
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: my-storage-box
|
||||||
|
snapshot_plan: null
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Reset a Storage Box password
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: my-storage-box
|
||||||
|
password: my-secret
|
||||||
|
state: reset_password
|
||||||
|
|
||||||
|
- name: Rollback a Storage Box to a Snapshot
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: my-storage-box
|
||||||
|
snapshot: 2025-12-03T13-47-47
|
||||||
|
state: rollback_snapshot
|
||||||
|
|
||||||
|
- name: Delete a Storage Box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: my-storage-box
|
||||||
|
state: absent
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
hcloud_storage_box:
|
||||||
|
description: Details about the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: ID of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 1937415
|
||||||
|
name:
|
||||||
|
description: Name of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: my-storage-box
|
||||||
|
storage_box_type:
|
||||||
|
description: Name of the Storage Box Type.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: bx11
|
||||||
|
location:
|
||||||
|
description: Name of the Location of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: fsn1
|
||||||
|
labels:
|
||||||
|
description: User-defined labels (key-value pairs) of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
sample:
|
||||||
|
env: prod
|
||||||
|
delete_protection:
|
||||||
|
description: Protect the Storage Box from deletion.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
access_settings:
|
||||||
|
description: Access settings of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
reachable_externally:
|
||||||
|
description: Whether access from outside the Hetzner network is allowed.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
samba_enabled:
|
||||||
|
description: Whether the Samba subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
ssh_enabled:
|
||||||
|
description: Whether the SSH subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
webdav_enabled:
|
||||||
|
description: Whether the WebDAV subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
zfs_enabled:
|
||||||
|
description: Whether the ZFS snapshot folder is visible.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
snapshot_plan:
|
||||||
|
description: Snapshot plan of the Storage Box.
|
||||||
|
returned: when enabled
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
max_snapshots:
|
||||||
|
description: Maximum amount of Snapshots that will be created by this Snapshot Plan.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10
|
||||||
|
hour:
|
||||||
|
description: Hour when the Snapshot Plan is executed (UTC).
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 3
|
||||||
|
minute:
|
||||||
|
description: Minute when the Snapshot Plan is executed (UTC).
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 30
|
||||||
|
day_of_week:
|
||||||
|
description: Day of the week when the Snapshot Plan is executed. Null means every day.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 1
|
||||||
|
day_of_month:
|
||||||
|
description: Day of the month when the Snapshot Plan is executed. Null means every day.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 30
|
||||||
|
username:
|
||||||
|
description: User name of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u505337
|
||||||
|
server:
|
||||||
|
description: FQDN of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u505337.your-storagebox.de
|
||||||
|
system:
|
||||||
|
description: Host system of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: HEL1-BX136
|
||||||
|
status:
|
||||||
|
description: Status of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: active
|
||||||
|
stats:
|
||||||
|
description: Statistics of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
size:
|
||||||
|
description: Current disk usage in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
size_data:
|
||||||
|
description: Current disk usage for data in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
size_snapshots:
|
||||||
|
description: Current disk usage for snapshots in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ..module_utils import storage_box
|
||||||
|
from ..module_utils.client import client_resource_not_found
|
||||||
|
from ..module_utils.experimental import storage_box_experimental_warning
|
||||||
|
from ..module_utils.hcloud import AnsibleHCloud, AnsibleModule
|
||||||
|
from ..module_utils.vendor.hcloud import HCloudException
|
||||||
|
from ..module_utils.vendor.hcloud.locations import Location
|
||||||
|
from ..module_utils.vendor.hcloud.storage_box_types import StorageBoxType
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
StorageBoxAccessSettings,
|
||||||
|
StorageBoxSnapshot,
|
||||||
|
StorageBoxSnapshotPlan,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleStorageBox(AnsibleHCloud):
|
||||||
|
represent = "storage_box"
|
||||||
|
|
||||||
|
storage_box: BoundStorageBox | None = None
|
||||||
|
|
||||||
|
def __init__(self, module: AnsibleModule):
|
||||||
|
storage_box_experimental_warning(module)
|
||||||
|
super().__init__(module)
|
||||||
|
|
||||||
|
def _prepare_result(self):
|
||||||
|
if self.storage_box is not None:
|
||||||
|
return storage_box.prepare_result(self.storage_box)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def _fetch(self):
|
||||||
|
if self.module.params.get("id") is not None:
|
||||||
|
self.storage_box = self.client.storage_boxes.get_by_id(self.module.params.get("id"))
|
||||||
|
else:
|
||||||
|
self.storage_box = self.client.storage_boxes.get_by_name(self.module.params.get("name"))
|
||||||
|
|
||||||
|
def _create(self):
|
||||||
|
self.fail_on_invalid_params(
|
||||||
|
required=["name", "storage_box_type", "location", "password"],
|
||||||
|
)
|
||||||
|
params = {
|
||||||
|
"name": self.module.params.get("name"),
|
||||||
|
"storage_box_type": StorageBoxType(self.module.params.get("storage_box_type")),
|
||||||
|
"location": Location(self.module.params.get("location")),
|
||||||
|
"password": self.module.params.get("password"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value := self.module.params.get("labels")) is not None:
|
||||||
|
params["labels"] = value
|
||||||
|
|
||||||
|
if (value := self.module.params.get("access_settings")) is not None:
|
||||||
|
params["access_settings"] = StorageBoxAccessSettings.from_dict(value)
|
||||||
|
|
||||||
|
if (value := self.module.params.get("ssh_keys")) is not None:
|
||||||
|
params["ssh_keys"] = value
|
||||||
|
|
||||||
|
if not self.module.check_mode:
|
||||||
|
resp = self.client.storage_boxes.create(**params)
|
||||||
|
self.storage_box = resp.storage_box
|
||||||
|
resp.action.wait_until_finished()
|
||||||
|
|
||||||
|
if (value := self.module.params.get("delete_protection")) is not None:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.change_protection(delete=value)
|
||||||
|
action.wait_until_finished()
|
||||||
|
|
||||||
|
if self.module.param_is_defined("snapshot_plan"):
|
||||||
|
if (value := self.module.params.get("snapshot_plan")) is not None:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.enable_snapshot_plan(StorageBoxSnapshotPlan.from_dict(value))
|
||||||
|
action.wait_until_finished()
|
||||||
|
|
||||||
|
if not self.module.check_mode:
|
||||||
|
self.storage_box.reload()
|
||||||
|
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
def _update(self):
|
||||||
|
need_reload = False
|
||||||
|
|
||||||
|
if (value := self.module.params.get("storage_box_type")) is not None:
|
||||||
|
if not self.storage_box.storage_box_type.has_id_or_name(value):
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.change_type(StorageBoxType(value))
|
||||||
|
action.wait_until_finished()
|
||||||
|
need_reload = True
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
if (value := self.module.params.get("access_settings")) is not None:
|
||||||
|
access_settings = StorageBoxAccessSettings.from_dict(value)
|
||||||
|
if self.storage_box.access_settings.to_payload() != access_settings.to_payload():
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.update_access_settings(access_settings)
|
||||||
|
action.wait_until_finished()
|
||||||
|
need_reload = True
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
if (value := self.module.params.get("delete_protection")) is not None:
|
||||||
|
if self.storage_box.protection["delete"] != value:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.change_protection(delete=value)
|
||||||
|
action.wait_until_finished()
|
||||||
|
need_reload = True
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
if self.module.param_is_defined("snapshot_plan"):
|
||||||
|
if (value := self.module.params.get("snapshot_plan")) is not None:
|
||||||
|
snapshot_plan = StorageBoxSnapshotPlan.from_dict(value)
|
||||||
|
if (
|
||||||
|
self.storage_box.snapshot_plan is None
|
||||||
|
or self.storage_box.snapshot_plan.to_payload() != snapshot_plan.to_payload()
|
||||||
|
):
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.enable_snapshot_plan(snapshot_plan)
|
||||||
|
action.wait_until_finished()
|
||||||
|
need_reload = True
|
||||||
|
self._mark_as_changed()
|
||||||
|
else:
|
||||||
|
if self.storage_box.snapshot_plan is not None:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.disable_snapshot_plan()
|
||||||
|
action.wait_until_finished()
|
||||||
|
need_reload = True
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
if (value := self.module.params.get("name")) is not None and value != self.storage_box.name:
|
||||||
|
self.fail_on_invalid_params(required=["id"])
|
||||||
|
params["name"] = value
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
if (value := self.module.params.get("labels")) is not None and value != self.storage_box.labels:
|
||||||
|
params["labels"] = value
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
# Update only if params holds changes or the data must be refreshed (actions
|
||||||
|
# were triggered)
|
||||||
|
if params or need_reload:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
self.storage_box = self.storage_box.update(**params)
|
||||||
|
|
||||||
|
def _delete(self):
|
||||||
|
if not self.module.check_mode:
|
||||||
|
resp = self.storage_box.delete()
|
||||||
|
resp.action.wait_until_finished()
|
||||||
|
|
||||||
|
self.storage_box = None
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
def present(self):
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box is None:
|
||||||
|
self._create()
|
||||||
|
else:
|
||||||
|
self._update()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
def absent(self):
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box is None:
|
||||||
|
return
|
||||||
|
self._delete()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
def reset_password(self):
|
||||||
|
self.fail_on_invalid_params(
|
||||||
|
required=["password"],
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box is None:
|
||||||
|
raise client_resource_not_found(
|
||||||
|
"storage box",
|
||||||
|
self.module.params.get("id") or self.module.params.get("name"),
|
||||||
|
)
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.reset_password(self.module.params.get("password"))
|
||||||
|
action.wait_until_finished()
|
||||||
|
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
def rollback_snapshot(self):
|
||||||
|
self.fail_on_invalid_params(
|
||||||
|
required=["snapshot"],
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box is None:
|
||||||
|
raise client_resource_not_found(
|
||||||
|
"storage box",
|
||||||
|
self.module.params.get("id") or self.module.params.get("name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box.rollback_snapshot(StorageBoxSnapshot(self.module.params.get("snapshot")))
|
||||||
|
action.wait_until_finished()
|
||||||
|
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_module(cls):
|
||||||
|
return AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
id={"type": "int"},
|
||||||
|
name={"type": "str"},
|
||||||
|
storage_box_type={"type": "str", "aliases": ["type"]},
|
||||||
|
location={"type": "str"},
|
||||||
|
password={"type": "str", "no_log": True},
|
||||||
|
ssh_keys={"type": "list", "elements": "str", "no_log": False},
|
||||||
|
labels={"type": "dict"},
|
||||||
|
access_settings={
|
||||||
|
"type": "dict",
|
||||||
|
"options": dict(
|
||||||
|
reachable_externally={"type": "bool", "default": False},
|
||||||
|
samba_enabled={"type": "bool", "default": False},
|
||||||
|
ssh_enabled={"type": "bool", "default": False},
|
||||||
|
webdav_enabled={"type": "bool", "default": False},
|
||||||
|
zfs_enabled={"type": "bool", "default": False},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
snapshot_plan={
|
||||||
|
"type": "dict",
|
||||||
|
"options": dict(
|
||||||
|
max_snapshots={"type": "int", "required": True},
|
||||||
|
hour={"type": "int", "required": True},
|
||||||
|
minute={"type": "int", "required": True},
|
||||||
|
day_of_week={"type": "int"},
|
||||||
|
day_of_month={"type": "int"},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
delete_protection={"type": "bool"},
|
||||||
|
snapshot={"type": "str"},
|
||||||
|
state={
|
||||||
|
"choices": ["absent", "present", "reset_password", "rollback_snapshot"],
|
||||||
|
"default": "present",
|
||||||
|
},
|
||||||
|
**super().base_module_arguments(),
|
||||||
|
),
|
||||||
|
required_one_of=[["id", "name"]],
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleStorageBox.define_module()
|
||||||
|
o = AnsibleStorageBox(module)
|
||||||
|
|
||||||
|
match module.params.get("state"):
|
||||||
|
case "reset_password":
|
||||||
|
o.reset_password()
|
||||||
|
case "rollback_snapshot":
|
||||||
|
o.rollback_snapshot()
|
||||||
|
case "absent":
|
||||||
|
o.absent()
|
||||||
|
case _:
|
||||||
|
o.present()
|
||||||
|
|
||||||
|
result = o.get_result()
|
||||||
|
|
||||||
|
# Legacy return value naming pattern
|
||||||
|
result["hcloud_storage_box"] = result.pop(o.represent)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
256
plugins/modules/storage_box_info.py
Normal file
256
plugins/modules/storage_box_info.py
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2025, 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 annotations
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: storage_box_info
|
||||||
|
|
||||||
|
short_description: Gather infos about Hetzner Storage Boxes.
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Gather infos about Hetzner Storage Boxes.
|
||||||
|
- See the L(Storage Boxes API documentation,https://docs.hetzner.cloud/reference/hetzner#storage-boxes) for more details.
|
||||||
|
- B(Experimental:) Storage Box support is experimental, breaking changes may occur within minor releases.
|
||||||
|
See https://github.com/ansible-collections/hetzner.hcloud/issues/756 for more details.
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Jonas Lammler (@jooola)
|
||||||
|
|
||||||
|
options:
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- ID of the Storage Box to get.
|
||||||
|
- If the ID is invalid, the module will fail.
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the Storage Box to get.
|
||||||
|
type: str
|
||||||
|
label_selector:
|
||||||
|
description:
|
||||||
|
- Label selector to filter the Storage Boxes to get.
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- hetzner.hcloud.hcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Gather all Storage Boxes
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
register: output
|
||||||
|
- name: Print the gathered infos
|
||||||
|
debug:
|
||||||
|
var: output.hcloud_storage_box_info
|
||||||
|
|
||||||
|
- name: Gather Storage Boxes by label
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
label_selector: env=prod
|
||||||
|
register: output
|
||||||
|
- name: Print the gathered infos
|
||||||
|
debug:
|
||||||
|
var: output.hcloud_storage_box_info
|
||||||
|
|
||||||
|
- name: Gather a Storage Box by name
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
name: backups
|
||||||
|
register: output
|
||||||
|
- name: Print the gathered infos
|
||||||
|
debug:
|
||||||
|
var: output.hcloud_storage_box_info[0]
|
||||||
|
|
||||||
|
- name: Gather a Storage Box by id
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
name: 12345
|
||||||
|
register: output
|
||||||
|
- name: Print the gathered infos
|
||||||
|
debug:
|
||||||
|
var: output.hcloud_storage_box_info[0]
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
hcloud_storage_box_info:
|
||||||
|
description: List of Storage Boxes.
|
||||||
|
returned: always
|
||||||
|
type: list
|
||||||
|
elements: dict
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: ID of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 1937415
|
||||||
|
name:
|
||||||
|
description: Name of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: my-storage-box
|
||||||
|
storage_box_type:
|
||||||
|
description: Name of the Storage Box Type.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: bx11
|
||||||
|
location:
|
||||||
|
description: Name of the Location of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: fsn1
|
||||||
|
labels:
|
||||||
|
description: User-defined labels (key-value pairs) of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
sample:
|
||||||
|
env: prod
|
||||||
|
delete_protection:
|
||||||
|
description: Protect the Storage Box from deletion.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
access_settings:
|
||||||
|
description: Access settings of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
reachable_externally:
|
||||||
|
description: Whether access from outside the Hetzner network is allowed.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
samba_enabled:
|
||||||
|
description: Whether the Samba subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
ssh_enabled:
|
||||||
|
description: Whether the SSH subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
webdav_enabled:
|
||||||
|
description: Whether the WebDAV subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
zfs_enabled:
|
||||||
|
description: Whether the ZFS snapshot folder is visible.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
username:
|
||||||
|
description: User name of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u505337
|
||||||
|
server:
|
||||||
|
description: FQDN of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u505337.your-storagebox.de
|
||||||
|
system:
|
||||||
|
description: Host system of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: HEL1-BX136
|
||||||
|
status:
|
||||||
|
description: Status of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: active
|
||||||
|
stats:
|
||||||
|
description: Statistics of the Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
size:
|
||||||
|
description: Current disk usage in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
size_data:
|
||||||
|
description: Current disk usage for data in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
size_snapshots:
|
||||||
|
description: Current disk usage for snapshots in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
from ..module_utils import storage_box
|
||||||
|
from ..module_utils.experimental import storage_box_experimental_warning
|
||||||
|
from ..module_utils.hcloud import AnsibleHCloud
|
||||||
|
from ..module_utils.vendor.hcloud import HCloudException
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleStorageBox(AnsibleHCloud):
|
||||||
|
represent = "storage_box"
|
||||||
|
|
||||||
|
storage_box: list[BoundStorageBox] | None = None
|
||||||
|
|
||||||
|
def __init__(self, module: AnsibleModule):
|
||||||
|
storage_box_experimental_warning(module)
|
||||||
|
super().__init__(module)
|
||||||
|
|
||||||
|
def _prepare_result(self):
|
||||||
|
result = []
|
||||||
|
for o in self.storage_box or []:
|
||||||
|
if o is not None:
|
||||||
|
result.append(storage_box.prepare_result(o))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
try:
|
||||||
|
if (id_ := self.module.params.get("id")) is not None:
|
||||||
|
self.storage_box = [self.client.storage_boxes.get_by_id(id_)]
|
||||||
|
elif (name := self.module.params.get("name")) is not None:
|
||||||
|
self.storage_box = [self.client.storage_boxes.get_by_name(name)]
|
||||||
|
else:
|
||||||
|
params = {}
|
||||||
|
if (label_selector := self.module.params.get("label_selector")) is not None:
|
||||||
|
params["label_selector"] = label_selector
|
||||||
|
self.storage_box = self.client.storage_boxes.get_all(**params)
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_module(cls):
|
||||||
|
return AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
id={"type": "int"},
|
||||||
|
name={"type": "str"},
|
||||||
|
label_selector={"type": "str"},
|
||||||
|
**super().base_module_arguments(),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleStorageBox.define_module()
|
||||||
|
o = AnsibleStorageBox(module)
|
||||||
|
|
||||||
|
o.fetch()
|
||||||
|
result = o.get_result()
|
||||||
|
|
||||||
|
# Legacy return value naming pattern
|
||||||
|
result["hcloud_storage_box_info"] = result.pop(o.represent)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
282
plugins/modules/storage_box_snapshot.py
Normal file
282
plugins/modules/storage_box_snapshot.py
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2025, 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 annotations
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: storage_box_snapshot
|
||||||
|
|
||||||
|
short_description: Create and manage Storage Box Snapshots in Hetzner.
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Create, update and delete Storage Box Snapshots in Hetzner.
|
||||||
|
- See the L(Storage Box Snapshots API documentation,https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots) for more details.
|
||||||
|
- B(Experimental:) Storage Box support is experimental, breaking changes may occur within minor releases.
|
||||||
|
See https://github.com/ansible-collections/hetzner.hcloud/issues/756 for more details.
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Jonas Lammler (@jooola)
|
||||||
|
|
||||||
|
options:
|
||||||
|
storage_box:
|
||||||
|
description:
|
||||||
|
- ID or Name of the parent Storage Box.
|
||||||
|
- Using the ID is preferred, to reduce the amount of API requests.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- ID of the Storage Box Snapshot to manage.
|
||||||
|
- Required when updating or deleting and if no Storage Box Snapshot O(name) is given.
|
||||||
|
- If the ID is invalid, the module will fail.
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the Storage Box Snapshot to manage.
|
||||||
|
- Storage Box Snapshot names are defined by the API and cannot be changed.
|
||||||
|
- Required when updating or deleting and if no Storage Box Snapshot O(id) is given.
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- Description of the Storage Box Snapshot.
|
||||||
|
type: str
|
||||||
|
labels:
|
||||||
|
description:
|
||||||
|
- User-defined labels (key-value pairs) for the Storage Box Snapshot.
|
||||||
|
type: dict
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- State of the Storage Box Snapshot.
|
||||||
|
default: present
|
||||||
|
choices: [absent, present]
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- hetzner.hcloud.hcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Create a Storage Box Snapshot
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
description: before app migration
|
||||||
|
labels:
|
||||||
|
env: prod
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Delete a Storage Box Snapshot by name
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
name: 2025-12-03T13-47-47
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Delete a Storage Box Snapshot by id
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: 497436
|
||||||
|
id: 405920
|
||||||
|
state: absent
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
hcloud_storage_box_snapshot:
|
||||||
|
description: Details about the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
storage_box:
|
||||||
|
description: ID of the parent Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 497436
|
||||||
|
id:
|
||||||
|
description: ID of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 405920
|
||||||
|
name:
|
||||||
|
description: Name of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: 2025-02-12T11-35-19
|
||||||
|
description:
|
||||||
|
description: Description of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: before app migration
|
||||||
|
labels:
|
||||||
|
description: User-defined labels (key-value pairs) of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
sample:
|
||||||
|
env: prod
|
||||||
|
stats:
|
||||||
|
description: Statistics of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
size:
|
||||||
|
description: Current storage requirements of the Snapshot in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
size_filesystem:
|
||||||
|
description: Size of the compressed file system contained in the Snapshot in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
is_automatic:
|
||||||
|
description: Whether the Storage Box Snapshot was created automatically.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
created:
|
||||||
|
description: Point in time when the Storage Box Snapshot was created (in RFC3339 format).
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: "2025-12-03T13:47:47Z"
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ..module_utils import storage_box, storage_box_snapshot
|
||||||
|
from ..module_utils.experimental import storage_box_experimental_warning
|
||||||
|
from ..module_utils.hcloud import AnsibleHCloud, AnsibleModule
|
||||||
|
from ..module_utils.vendor.hcloud import HCloudException
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
BoundStorageBoxSnapshot,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleStorageBoxSnapshot(AnsibleHCloud):
|
||||||
|
represent = "storage_box_snapshot"
|
||||||
|
|
||||||
|
storage_box: BoundStorageBox | None = None
|
||||||
|
storage_box_snapshot: BoundStorageBoxSnapshot | None = None
|
||||||
|
|
||||||
|
def __init__(self, module: AnsibleModule):
|
||||||
|
storage_box_experimental_warning(module)
|
||||||
|
super().__init__(module)
|
||||||
|
|
||||||
|
def _prepare_result(self):
|
||||||
|
if self.storage_box_snapshot is None:
|
||||||
|
return {}
|
||||||
|
return storage_box_snapshot.prepare_result(self.storage_box_snapshot)
|
||||||
|
|
||||||
|
def _fetch(self):
|
||||||
|
self.storage_box = storage_box.get(self.client.storage_boxes, self.module.params.get("storage_box"))
|
||||||
|
|
||||||
|
if (value := self.module.params.get("id")) is not None:
|
||||||
|
self.storage_box_snapshot = self.storage_box.get_snapshot_by_id(value)
|
||||||
|
elif (value := self.module.params.get("name")) is not None:
|
||||||
|
self.storage_box_snapshot = self.storage_box.get_snapshot_by_name(value)
|
||||||
|
|
||||||
|
def _create(self):
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if (value := self.module.params.get("description")) is not None:
|
||||||
|
params["description"] = value
|
||||||
|
|
||||||
|
if (value := self.module.params.get("labels")) is not None:
|
||||||
|
params["labels"] = value
|
||||||
|
|
||||||
|
if not self.module.check_mode:
|
||||||
|
resp = self.storage_box.create_snapshot(**params)
|
||||||
|
self.storage_box_snapshot = resp.snapshot
|
||||||
|
resp.action.wait_until_finished()
|
||||||
|
|
||||||
|
self.storage_box_snapshot.reload()
|
||||||
|
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
def _update(self):
|
||||||
|
self.fail_on_invalid_params(
|
||||||
|
required_one_of=[["id", "name"]],
|
||||||
|
)
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
if (value := self.module.params.get("description")) is not None:
|
||||||
|
if value != self.storage_box_snapshot.description:
|
||||||
|
params["description"] = value
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
if (value := self.module.params.get("labels")) is not None:
|
||||||
|
if value != self.storage_box_snapshot.labels:
|
||||||
|
params["labels"] = value
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
# Update only if params holds changes
|
||||||
|
if params:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
self.storage_box_snapshot = self.storage_box_snapshot.update(**params)
|
||||||
|
|
||||||
|
def _delete(self):
|
||||||
|
if not self.module.check_mode:
|
||||||
|
resp = self.storage_box_snapshot.delete()
|
||||||
|
resp.action.wait_until_finished()
|
||||||
|
|
||||||
|
self.storage_box_snapshot = None
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
def present(self):
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box_snapshot is None:
|
||||||
|
self._create()
|
||||||
|
else:
|
||||||
|
self._update()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
def absent(self):
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box_snapshot is None:
|
||||||
|
return
|
||||||
|
self._delete()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_module(cls):
|
||||||
|
return AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
storage_box={"type": "str", "required": True},
|
||||||
|
id={"type": "int"},
|
||||||
|
name={"type": "str"},
|
||||||
|
description={"type": "str"},
|
||||||
|
labels={"type": "dict"},
|
||||||
|
state={
|
||||||
|
"choices": ["absent", "present"],
|
||||||
|
"default": "present",
|
||||||
|
},
|
||||||
|
**super().base_module_arguments(),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleStorageBoxSnapshot.define_module()
|
||||||
|
o = AnsibleStorageBoxSnapshot(module)
|
||||||
|
|
||||||
|
match module.params.get("state"):
|
||||||
|
case "absent":
|
||||||
|
o.absent()
|
||||||
|
case _:
|
||||||
|
o.present()
|
||||||
|
|
||||||
|
result = o.get_result()
|
||||||
|
|
||||||
|
# Legacy return value naming pattern
|
||||||
|
result["hcloud_storage_box_snapshot"] = result.pop(o.represent)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
213
plugins/modules/storage_box_snapshot_info.py
Normal file
213
plugins/modules/storage_box_snapshot_info.py
Normal file
|
|
@ -0,0 +1,213 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2025, 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 annotations
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: storage_box_snapshot_info
|
||||||
|
|
||||||
|
short_description: Gather infos about Hetzner Storage Box Snapshots.
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Gather infos about Hetzner Storage Box Snapshots.
|
||||||
|
- See the L(Storage Boxes API documentation,https://docs.hetzner.cloud/reference/hetzner#storage-boxes) for more details.
|
||||||
|
- B(Experimental:) Storage Box support is experimental, breaking changes may occur within minor releases.
|
||||||
|
See https://github.com/ansible-collections/hetzner.hcloud/issues/756 for more details.
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Jonas Lammler (@jooola)
|
||||||
|
|
||||||
|
options:
|
||||||
|
storage_box:
|
||||||
|
description:
|
||||||
|
- ID or Name of the parent Storage Box.
|
||||||
|
- Using the ID is preferred, to reduce the amount of API requests.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- ID of the Storage Box Snapshot to get.
|
||||||
|
- If the ID is invalid, the module will fail.
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the Storage Box Snapshot to get.
|
||||||
|
type: str
|
||||||
|
label_selector:
|
||||||
|
description:
|
||||||
|
- Label selector to filter the Storage Box Snapshots to get.
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- hetzner.hcloud.hcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Gather all Storage Box Snapshots
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Gather Storage Box Snapshots by label
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
label_selector: key=value
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Gather Storage Box Snapshot by id
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: 497436
|
||||||
|
id: 405920
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Gather Storage Box Snapshot by name
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
name: 2025-02-12T11-35-19
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Print the gathered infos
|
||||||
|
debug:
|
||||||
|
var: output.hcloud_storage_box_snapshot_info
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
hcloud_storage_box_snapshot_info:
|
||||||
|
description: List of Storage Box Snapshots.
|
||||||
|
returned: always
|
||||||
|
type: list
|
||||||
|
contains:
|
||||||
|
storage_box:
|
||||||
|
description: ID of the parent Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 497436
|
||||||
|
id:
|
||||||
|
description: ID of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 405920
|
||||||
|
name:
|
||||||
|
description: Name of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: 2025-02-12T11-35-19
|
||||||
|
description:
|
||||||
|
description: Description of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: before app migration
|
||||||
|
labels:
|
||||||
|
description: User-defined labels (key-value pairs) of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
sample:
|
||||||
|
env: prod
|
||||||
|
stats:
|
||||||
|
description: Statistics of the Storage Box Snapshot.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
size:
|
||||||
|
description: Current storage requirements of the Snapshot in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
size_filesystem:
|
||||||
|
description: Size of the compressed file system contained in the Snapshot in bytes.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 10485760
|
||||||
|
is_automatic:
|
||||||
|
description: Whether the Storage Box Snapshot was created automatically.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
created:
|
||||||
|
description: Point in time when the Storage Box Snapshot was created (in RFC3339 format).
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: "2025-12-03T13:47:47Z"
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ..module_utils import storage_box, storage_box_snapshot
|
||||||
|
from ..module_utils.experimental import storage_box_experimental_warning
|
||||||
|
from ..module_utils.hcloud import AnsibleHCloud, AnsibleModule
|
||||||
|
from ..module_utils.vendor.hcloud import HCloudException
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
BoundStorageBoxSnapshot,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleStorageBoxSnapshotInfo(AnsibleHCloud):
|
||||||
|
represent = "storage_box_snapshots"
|
||||||
|
|
||||||
|
storage_box: BoundStorageBox | None = None
|
||||||
|
storage_box_snapshots: list[BoundStorageBoxSnapshot] | None = None
|
||||||
|
|
||||||
|
def __init__(self, module: AnsibleModule):
|
||||||
|
storage_box_experimental_warning(module)
|
||||||
|
super().__init__(module)
|
||||||
|
|
||||||
|
def _prepare_result(self):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for o in self.storage_box_snapshots or []:
|
||||||
|
if o is not None:
|
||||||
|
result.append(storage_box_snapshot.prepare_result(o))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
try:
|
||||||
|
self.storage_box = storage_box.get(
|
||||||
|
self.client.storage_boxes,
|
||||||
|
self.module.params.get("storage_box"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (id_ := self.module.params.get("id")) is not None:
|
||||||
|
self.storage_box_snapshots = [self.storage_box.get_snapshot_by_id(id_)]
|
||||||
|
elif (name := self.module.params.get("name")) is not None:
|
||||||
|
self.storage_box_snapshots = [self.storage_box.get_snapshot_by_name(name)]
|
||||||
|
else:
|
||||||
|
params = {}
|
||||||
|
if (value := self.module.params.get("label_selector")) is not None:
|
||||||
|
params["label_selector"] = value
|
||||||
|
self.storage_box_snapshots = self.storage_box.get_snapshot_all(**params)
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_module(cls):
|
||||||
|
return AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
storage_box={"type": "str", "required": True},
|
||||||
|
id={"type": "int"},
|
||||||
|
name={"type": "str"},
|
||||||
|
label_selector={"type": "str"},
|
||||||
|
**super().base_module_arguments(),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleStorageBoxSnapshotInfo.define_module()
|
||||||
|
o = AnsibleStorageBoxSnapshotInfo(module)
|
||||||
|
|
||||||
|
o.fetch()
|
||||||
|
result = o.get_result()
|
||||||
|
|
||||||
|
# Legacy return value naming pattern
|
||||||
|
result["hcloud_storage_box_snapshot_info"] = result.pop(o.represent)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
476
plugins/modules/storage_box_subaccount.py
Normal file
476
plugins/modules/storage_box_subaccount.py
Normal file
|
|
@ -0,0 +1,476 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2025, 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 annotations
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: storage_box_subaccount
|
||||||
|
|
||||||
|
short_description: Create and manage Storage Box Subaccounts in Hetzner.
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Create, update and delete Storage Box Subaccounts in Hetzner.
|
||||||
|
- See the L(Storage Box Subaccounts API documentation,https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts) for more details.
|
||||||
|
- B(Experimental:) Storage Box support is experimental, breaking changes may occur within minor releases.
|
||||||
|
See https://github.com/ansible-collections/hetzner.hcloud/issues/756 for more details.
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Jonas Lammler (@jooola)
|
||||||
|
|
||||||
|
options:
|
||||||
|
storage_box:
|
||||||
|
description:
|
||||||
|
- ID or Name of the parent Storage Box.
|
||||||
|
- Using the ID is preferred, to reduce the amount of API requests.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- ID of the Storage Box Subaccount to manage.
|
||||||
|
- Required if no Storage Box Subaccount O(name) is given.
|
||||||
|
- If the ID is invalid, the module will fail.
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the Storage Box Subaccount to manage.
|
||||||
|
- Required if no Storage Box Subaccount O(id) is given.
|
||||||
|
- Required if the Storage Box Subaccount does not exist.
|
||||||
|
- Because the API resource does not have this property, the name is stored
|
||||||
|
in the Storage Box Subaccount labels. This ensures that the module is
|
||||||
|
idempotent, and removes the need to use different module arguments for
|
||||||
|
create and update.
|
||||||
|
type: str
|
||||||
|
password:
|
||||||
|
description:
|
||||||
|
- Password for the Storage Box Subaccount.
|
||||||
|
- Required if the Storage Box Subaccount does not exist or when O(state=reset_password).
|
||||||
|
type: str
|
||||||
|
home_directory:
|
||||||
|
description:
|
||||||
|
- Home directory of the Storage Box Subaccount.
|
||||||
|
- Required if the Storage Box Subaccount does not exist.
|
||||||
|
type: str
|
||||||
|
access_settings:
|
||||||
|
description:
|
||||||
|
- Access settings of the Storage Box Subaccount.
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
reachable_externally:
|
||||||
|
description:
|
||||||
|
- Whether access from outside the Hetzner network is allowed.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
samba_enabled:
|
||||||
|
description:
|
||||||
|
- Whether the Samba subsystem is enabled.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
ssh_enabled:
|
||||||
|
description:
|
||||||
|
- Whether the SSH subsystem is enabled.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
webdav_enabled:
|
||||||
|
description:
|
||||||
|
- Whether the WebDAV subsystem is enabled.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
readonly:
|
||||||
|
description:
|
||||||
|
- Whether the Subaccount is read-only.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- Description of the Storage Box Subaccount.
|
||||||
|
type: str
|
||||||
|
labels:
|
||||||
|
description:
|
||||||
|
- User-defined labels (key-value pairs) for the Storage Box Subaccount.
|
||||||
|
type: dict
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- State of the Storage Box Subaccount.
|
||||||
|
- C(reset_password) is not idempotent.
|
||||||
|
default: present
|
||||||
|
choices: [absent, present, reset_password]
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- hetzner.hcloud.hcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Create a Storage Box Subaccount
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
name: subaccount1
|
||||||
|
home_directory: backups/subaccount1
|
||||||
|
password: secret
|
||||||
|
access_settings:
|
||||||
|
reachable_externally: false
|
||||||
|
ssh_enabled: true
|
||||||
|
samba_enabled: false
|
||||||
|
webdav_enabled: false
|
||||||
|
readonly: false
|
||||||
|
labels:
|
||||||
|
env: prod
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Reset a Storage Box Subaccount password
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
name: subaccount1
|
||||||
|
password: secret
|
||||||
|
state: reset_password
|
||||||
|
|
||||||
|
- name: Delete a Storage Box Subaccount by name
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: my-storage-box
|
||||||
|
name: subaccount1
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: Delete a Storage Box Subaccount by id
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: 497436
|
||||||
|
id: 158045
|
||||||
|
state: absent
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
hcloud_storage_box_subaccount:
|
||||||
|
description: Details about the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
storage_box:
|
||||||
|
description: ID of the parent Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 497436
|
||||||
|
id:
|
||||||
|
description: ID of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 158045
|
||||||
|
name:
|
||||||
|
description: Name of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: subaccount1
|
||||||
|
description:
|
||||||
|
description: Description of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: backups from subaccount1
|
||||||
|
home_directory:
|
||||||
|
description: Home directory of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: backups/subaccount1
|
||||||
|
username:
|
||||||
|
description: Username of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u514605-sub1
|
||||||
|
server:
|
||||||
|
description: FQDN of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u514605-sub1.your-storagebox.de
|
||||||
|
access_settings:
|
||||||
|
description: Access settings of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
reachable_externally:
|
||||||
|
description: Whether access from outside the Hetzner network is allowed.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
samba_enabled:
|
||||||
|
description: Whether the Samba subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
ssh_enabled:
|
||||||
|
description: Whether the SSH subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
webdav_enabled:
|
||||||
|
description: Whether the WebDAV subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
readonly:
|
||||||
|
description: Whether the Subaccount is read-only.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
labels:
|
||||||
|
description: User-defined labels (key-value pairs) of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
sample:
|
||||||
|
env: prod
|
||||||
|
created:
|
||||||
|
description: Point in time when the Storage Box Subaccount was created (in RFC3339 format).
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: "2025-12-03T13:47:47Z"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import string
|
||||||
|
|
||||||
|
from ..module_utils import storage_box, storage_box_subaccount
|
||||||
|
from ..module_utils.client import client_resource_not_found
|
||||||
|
from ..module_utils.experimental import storage_box_experimental_warning
|
||||||
|
from ..module_utils.hcloud import AnsibleHCloud, AnsibleModule
|
||||||
|
from ..module_utils.storage_box_subaccount import NAME_LABEL_KEY
|
||||||
|
from ..module_utils.vendor.hcloud import HCloudException
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
BoundStorageBoxSubaccount,
|
||||||
|
StorageBoxSubaccountAccessSettings,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleStorageBoxSubaccount(AnsibleHCloud):
|
||||||
|
represent = "storage_box_subaccount"
|
||||||
|
|
||||||
|
storage_box: BoundStorageBox | None = None
|
||||||
|
storage_box_subaccount: BoundStorageBoxSubaccount | None = None
|
||||||
|
storage_box_subaccount_name: str | None = None
|
||||||
|
|
||||||
|
def __init__(self, module: AnsibleModule):
|
||||||
|
storage_box_experimental_warning(module)
|
||||||
|
super().__init__(module)
|
||||||
|
|
||||||
|
def _prepare_result(self):
|
||||||
|
if self.storage_box_subaccount is None:
|
||||||
|
return {}
|
||||||
|
return storage_box_subaccount.prepare_result(self.storage_box_subaccount, self.storage_box_subaccount_name)
|
||||||
|
|
||||||
|
def _fetch(self):
|
||||||
|
self.storage_box = storage_box.get(self.client.storage_boxes, self.module.params.get("storage_box"))
|
||||||
|
|
||||||
|
if (value := self.module.params.get("id")) is not None:
|
||||||
|
self.storage_box_subaccount = self.storage_box.get_subaccount_by_id(value)
|
||||||
|
elif (value := self.module.params.get("name")) is not None:
|
||||||
|
self.storage_box_subaccount = storage_box_subaccount.get_by_name(self.storage_box, value)
|
||||||
|
|
||||||
|
# Workaround the missing name property
|
||||||
|
# Get the name of the resource from the labels
|
||||||
|
if self.storage_box_subaccount is not None:
|
||||||
|
self.storage_box_subaccount_name = self.storage_box_subaccount.labels.pop(NAME_LABEL_KEY)
|
||||||
|
|
||||||
|
def _create(self):
|
||||||
|
self.fail_on_invalid_params(
|
||||||
|
required=["name", "home_directory", "password"],
|
||||||
|
)
|
||||||
|
params = {
|
||||||
|
"home_directory": self.module.params.get("home_directory"),
|
||||||
|
"password": self.module.params.get("password"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value := self.module.params.get("description")) is not None:
|
||||||
|
params["description"] = value
|
||||||
|
|
||||||
|
if (value := self.module.params.get("labels")) is not None:
|
||||||
|
params["labels"] = value
|
||||||
|
|
||||||
|
if (value := self.module.params.get("access_settings")) is not None:
|
||||||
|
params["access_settings"] = StorageBoxSubaccountAccessSettings.from_dict(value)
|
||||||
|
|
||||||
|
# Workaround the missing name property
|
||||||
|
# Save the name of the resource in the labels
|
||||||
|
if "labels" not in params:
|
||||||
|
params["labels"] = {}
|
||||||
|
params["labels"][NAME_LABEL_KEY] = self.module.params.get("name")
|
||||||
|
|
||||||
|
if not self.module.check_mode:
|
||||||
|
resp = self.storage_box.create_subaccount(**params)
|
||||||
|
self.storage_box_subaccount = resp.subaccount
|
||||||
|
resp.action.wait_until_finished()
|
||||||
|
|
||||||
|
self.storage_box_subaccount.reload()
|
||||||
|
self.storage_box_subaccount_name = self.storage_box_subaccount.labels.pop(NAME_LABEL_KEY)
|
||||||
|
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
def _update(self):
|
||||||
|
need_reload = False
|
||||||
|
|
||||||
|
if (value := self.module.params.get("home_directory")) is not None:
|
||||||
|
if self.storage_box_subaccount.home_directory != value:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box_subaccount.change_home_directory(value)
|
||||||
|
action.wait_until_finished()
|
||||||
|
need_reload = True
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
if (value := self.module.params.get("access_settings")) is not None:
|
||||||
|
access_settings = StorageBoxSubaccountAccessSettings.from_dict(value)
|
||||||
|
if self.storage_box_subaccount.access_settings.to_payload() != access_settings.to_payload():
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box_subaccount.update_access_settings(access_settings)
|
||||||
|
action.wait_until_finished()
|
||||||
|
need_reload = True
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
params = {}
|
||||||
|
if (value := self.module.params.get("description")) is not None:
|
||||||
|
if value != self.storage_box_subaccount.description:
|
||||||
|
params["description"] = value
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
if (value := self.module.params.get("labels")) is not None:
|
||||||
|
if value != self.storage_box_subaccount.labels:
|
||||||
|
params["labels"] = value
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
# Workaround the missing name property
|
||||||
|
# Preserve resource name in the labels, name update happens below
|
||||||
|
params["labels"][NAME_LABEL_KEY] = self.storage_box_subaccount_name
|
||||||
|
|
||||||
|
# Workaround the missing name property
|
||||||
|
# Update resource name in the labels
|
||||||
|
if (value := self.module.params.get("name")) is not None:
|
||||||
|
if value != self.storage_box_subaccount_name:
|
||||||
|
self.fail_on_invalid_params(required=["id"])
|
||||||
|
if "labels" not in params:
|
||||||
|
params["labels"] = self.storage_box_subaccount.labels
|
||||||
|
params["labels"][NAME_LABEL_KEY] = value
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
# Update only if params holds changes or actions were triggered
|
||||||
|
if params or need_reload:
|
||||||
|
if not self.module.check_mode:
|
||||||
|
self.storage_box_subaccount = self.storage_box_subaccount.update(**params)
|
||||||
|
self.storage_box_subaccount_name = self.storage_box_subaccount.labels.pop(NAME_LABEL_KEY)
|
||||||
|
|
||||||
|
def _delete(self):
|
||||||
|
if not self.module.check_mode:
|
||||||
|
resp = self.storage_box_subaccount.delete()
|
||||||
|
resp.action.wait_until_finished()
|
||||||
|
|
||||||
|
self.storage_box_subaccount = None
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
def present(self):
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box_subaccount is None:
|
||||||
|
self._create()
|
||||||
|
else:
|
||||||
|
self._update()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
def absent(self):
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box_subaccount is None:
|
||||||
|
return
|
||||||
|
self._delete()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
def reset_password(self):
|
||||||
|
self.fail_on_invalid_params(
|
||||||
|
required=["password"],
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
self._fetch()
|
||||||
|
if self.storage_box_subaccount is None:
|
||||||
|
raise client_resource_not_found(
|
||||||
|
"storage box",
|
||||||
|
self.module.params.get("id") or self.module.params.get("name"),
|
||||||
|
)
|
||||||
|
if not self.module.check_mode:
|
||||||
|
action = self.storage_box_subaccount.reset_password(self.module.params.get("password"))
|
||||||
|
action.wait_until_finished()
|
||||||
|
|
||||||
|
self._mark_as_changed()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_module(cls):
|
||||||
|
return AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
storage_box={"type": "str", "required": True},
|
||||||
|
id={"type": "int"},
|
||||||
|
name={"type": "str"},
|
||||||
|
home_directory={"type": "str"},
|
||||||
|
password={"type": "str", "no_log": True},
|
||||||
|
description={"type": "str"},
|
||||||
|
labels={"type": "dict"},
|
||||||
|
access_settings={
|
||||||
|
"type": "dict",
|
||||||
|
"options": dict(
|
||||||
|
reachable_externally={"type": "bool", "default": False},
|
||||||
|
samba_enabled={"type": "bool", "default": False},
|
||||||
|
ssh_enabled={"type": "bool", "default": False},
|
||||||
|
webdav_enabled={"type": "bool", "default": False},
|
||||||
|
readonly={"type": "bool", "default": False},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
state={
|
||||||
|
"choices": ["absent", "present", "reset_password"],
|
||||||
|
"default": "present",
|
||||||
|
},
|
||||||
|
**super().base_module_arguments(),
|
||||||
|
),
|
||||||
|
required_one_of=[["id", "name"]],
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleStorageBoxSubaccount.define_module()
|
||||||
|
o = AnsibleStorageBoxSubaccount(module)
|
||||||
|
|
||||||
|
# Workaround the missing name property
|
||||||
|
# Validate name
|
||||||
|
if (value := module.params.get("name")) is not None:
|
||||||
|
if len(value) < 1:
|
||||||
|
module.fail_json(f"name '{value}' must be at least 1 character long")
|
||||||
|
|
||||||
|
allowed_chars = string.ascii_letters + string.digits + "-"
|
||||||
|
has_letters = False
|
||||||
|
for c in value:
|
||||||
|
if c in string.ascii_letters:
|
||||||
|
has_letters = True
|
||||||
|
if c in allowed_chars:
|
||||||
|
continue
|
||||||
|
module.fail_json(f"name '{value}' must only have allowed characters: {allowed_chars}")
|
||||||
|
if not has_letters:
|
||||||
|
module.fail_json(f"name '{value}' must contain at least one letter")
|
||||||
|
|
||||||
|
match module.params.get("state"):
|
||||||
|
case "reset_password":
|
||||||
|
o.reset_password()
|
||||||
|
case "absent":
|
||||||
|
o.absent()
|
||||||
|
case _:
|
||||||
|
o.present()
|
||||||
|
|
||||||
|
result = o.get_result()
|
||||||
|
|
||||||
|
# Legacy return value naming pattern
|
||||||
|
result["hcloud_storage_box_subaccount"] = result.pop(o.represent)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
242
plugins/modules/storage_box_subaccount_info.py
Normal file
242
plugins/modules/storage_box_subaccount_info.py
Normal file
|
|
@ -0,0 +1,242 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2025, 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 annotations
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: storage_box_subaccount_info
|
||||||
|
|
||||||
|
short_description: Gather infos about Hetzner Storage Box Subaccounts.
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Gather infos about Hetzner Storage Box Subaccounts.
|
||||||
|
- See the L(Storage Box Subaccounts API documentation,https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts) for more details.
|
||||||
|
- B(Experimental:) Storage Box support is experimental, breaking changes may occur within minor releases.
|
||||||
|
See https://github.com/ansible-collections/hetzner.hcloud/issues/756 for more details.
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Jonas Lammler (@jooola)
|
||||||
|
|
||||||
|
options:
|
||||||
|
storage_box:
|
||||||
|
description:
|
||||||
|
- ID or Name of the parent Storage Box.
|
||||||
|
- Using the ID is preferred, to reduce the amount of API requests.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- ID of the Storage Box Subaccount to get.
|
||||||
|
- If the ID is invalid, the module will fail.
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the Storage Box Subaccount to get.
|
||||||
|
type: str
|
||||||
|
label_selector:
|
||||||
|
description:
|
||||||
|
- Label selector to filter the Storage Box Subaccounts to get.
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- hetzner.hcloud.hcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Gather all Storage Box Subaccounts
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Gather Storage Box Subaccounts by label
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
label_selector: env=prod
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Gather a Storage Box Subaccount by name
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
name: subaccount1
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Gather a Storage Box Subaccount by id
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
name: 12345
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Print the gathered infos
|
||||||
|
debug:
|
||||||
|
var: output.hcloud_storage_box_subaccount_info
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
hcloud_storage_box_subaccount_info:
|
||||||
|
description: List of Storage Box Subaccounts.
|
||||||
|
returned: always
|
||||||
|
type: list
|
||||||
|
elements: dict
|
||||||
|
contains:
|
||||||
|
storage_box:
|
||||||
|
description: ID of the parent Storage Box.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 514605
|
||||||
|
id:
|
||||||
|
description: ID of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: int
|
||||||
|
sample: 158045
|
||||||
|
name:
|
||||||
|
description: Name of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: subaccount1
|
||||||
|
description:
|
||||||
|
description: Description of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: backups from subaccount1
|
||||||
|
home_directory:
|
||||||
|
description: Home directory of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: backups/subaccount1
|
||||||
|
username:
|
||||||
|
description: Username of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u514605-sub1
|
||||||
|
server:
|
||||||
|
description: FQDN of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: u514605-sub1.your-storagebox.de
|
||||||
|
access_settings:
|
||||||
|
description: Access settings of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
reachable_externally:
|
||||||
|
description: Whether access from outside the Hetzner network is allowed.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
samba_enabled:
|
||||||
|
description: Whether the Samba subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
ssh_enabled:
|
||||||
|
description: Whether the SSH subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
webdav_enabled:
|
||||||
|
description: Whether the WebDAV subsystem is enabled.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
readonly:
|
||||||
|
description: Whether the Subaccount is read-only.
|
||||||
|
returned: always
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
labels:
|
||||||
|
description: User-defined labels (key-value pairs) of the Storage Box Subaccount.
|
||||||
|
returned: always
|
||||||
|
type: dict
|
||||||
|
sample:
|
||||||
|
env: prod
|
||||||
|
created:
|
||||||
|
description: Point in time when the Storage Box Subaccount was created (in RFC3339 format).
|
||||||
|
returned: always
|
||||||
|
type: str
|
||||||
|
sample: "2025-12-03T13:47:47Z"
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
from ..module_utils import storage_box, storage_box_subaccount
|
||||||
|
from ..module_utils.experimental import storage_box_experimental_warning
|
||||||
|
from ..module_utils.hcloud import AnsibleHCloud
|
||||||
|
from ..module_utils.storage_box_subaccount import NAME_LABEL_KEY
|
||||||
|
from ..module_utils.vendor.hcloud import HCloudException
|
||||||
|
from ..module_utils.vendor.hcloud.storage_boxes import (
|
||||||
|
BoundStorageBox,
|
||||||
|
BoundStorageBoxSubaccount,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleStorageBoxSubaccountInfo(AnsibleHCloud):
|
||||||
|
represent = "storage_box_subaccounts"
|
||||||
|
|
||||||
|
storage_box: BoundStorageBox | None = None
|
||||||
|
storage_box_subaccounts: list[BoundStorageBoxSubaccount] | None = None
|
||||||
|
|
||||||
|
def __init__(self, module: AnsibleModule):
|
||||||
|
storage_box_experimental_warning(module)
|
||||||
|
super().__init__(module)
|
||||||
|
|
||||||
|
def _prepare_result(self):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for o in self.storage_box_subaccounts or []:
|
||||||
|
if o is not None:
|
||||||
|
# Workaround the missing name property
|
||||||
|
# Get the name of the resource from the labels
|
||||||
|
name = o.labels.pop(NAME_LABEL_KEY)
|
||||||
|
|
||||||
|
result.append(storage_box_subaccount.prepare_result(o, name))
|
||||||
|
return result
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
try:
|
||||||
|
self.storage_box = storage_box.get(
|
||||||
|
self.client.storage_boxes,
|
||||||
|
self.module.params.get("storage_box"),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (value := self.module.params.get("id")) is not None:
|
||||||
|
self.storage_box_subaccounts = [self.storage_box.get_subaccount_by_id(value)]
|
||||||
|
elif (value := self.module.params.get("name")) is not None:
|
||||||
|
self.storage_box_subaccounts = [storage_box_subaccount.get_by_name(self.storage_box, value)]
|
||||||
|
else:
|
||||||
|
params = {}
|
||||||
|
if (value := self.module.params.get("label_selector")) is not None:
|
||||||
|
params["label_selector"] = value
|
||||||
|
self.storage_box_subaccounts = self.storage_box.get_subaccount_all(**params)
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_module(cls):
|
||||||
|
return AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
storage_box={"type": "str", "required": True},
|
||||||
|
id={"type": "int"},
|
||||||
|
name={"type": "str"},
|
||||||
|
label_selector={"type": "str"},
|
||||||
|
**super().base_module_arguments(),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleStorageBoxSubaccountInfo.define_module()
|
||||||
|
o = AnsibleStorageBoxSubaccountInfo(module)
|
||||||
|
|
||||||
|
o.fetch()
|
||||||
|
result = o.get_result()
|
||||||
|
|
||||||
|
# Legacy return value naming pattern
|
||||||
|
result["hcloud_storage_box_subaccount_info"] = result.pop(o.represent)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
194
plugins/modules/storage_box_type_info.py
Normal file
194
plugins/modules/storage_box_type_info.py
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2025, 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 annotations
|
||||||
|
|
||||||
|
DOCUMENTATION = """
|
||||||
|
---
|
||||||
|
module: storage_box_type_info
|
||||||
|
|
||||||
|
short_description: Gather infos about Hetzner Storage Box Types.
|
||||||
|
|
||||||
|
description:
|
||||||
|
- Gather infos about available Hetzner Storage Box Types.
|
||||||
|
- See the L(Storage Box Types documentation,https://docs.hetzner.cloud/reference/hetzner#storage-box-types) for more details.
|
||||||
|
- B(Experimental:) Storage Box support is experimental, breaking changes may occur within minor releases.
|
||||||
|
See https://github.com/ansible-collections/hetzner.hcloud/issues/756 for more details.
|
||||||
|
|
||||||
|
author:
|
||||||
|
- Jonas Lammler (@jooola)
|
||||||
|
|
||||||
|
options:
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- ID of the Storage Box Type to get.
|
||||||
|
- If the ID is invalid, the module will fail.
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the Storage Box Type to get.
|
||||||
|
type: str
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- hetzner.hcloud.hcloud
|
||||||
|
"""
|
||||||
|
|
||||||
|
EXAMPLES = """
|
||||||
|
- name: Gather Storage Box Types infos
|
||||||
|
hetzner.hcloud.storage_box_type_info:
|
||||||
|
register: output
|
||||||
|
|
||||||
|
- name: Print the gathered infos
|
||||||
|
debug:
|
||||||
|
var: output.hcloud_storage_box_type_info
|
||||||
|
"""
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
hcloud_storage_box_type_info:
|
||||||
|
description: List of Storage Box Types.
|
||||||
|
returned: always
|
||||||
|
type: list
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: ID of the Storage Box Type.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 1937415
|
||||||
|
name:
|
||||||
|
description: Name of the Storage Box Type.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: bx21
|
||||||
|
description:
|
||||||
|
description: Description of the Storage Box Type.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: BX21
|
||||||
|
snapshot_limit:
|
||||||
|
description: Maximum number of allowed manual snapshots.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 10
|
||||||
|
automatic_snapshot_limit:
|
||||||
|
description: Maximum number of snapshots created automatically by a snapshot plan.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 10
|
||||||
|
subaccounts_limit:
|
||||||
|
description: Maximum number of subaccounts.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 200
|
||||||
|
size:
|
||||||
|
description: Available storage in bytes.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 1099511627776
|
||||||
|
deprecation:
|
||||||
|
description: Deprecation details about the Storage Box Type.
|
||||||
|
returned: when deprecated
|
||||||
|
type: dict
|
||||||
|
contains:
|
||||||
|
announced:
|
||||||
|
description: Date when the deprecation was announced.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: "2025-06-02T00:00:00Z"
|
||||||
|
unavailable_after:
|
||||||
|
description: |
|
||||||
|
Date when the resource will stop being available.
|
||||||
|
|
||||||
|
The resource will be removed from the list endpoint, but details
|
||||||
|
about the resource can be fetched using its ID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: "2025-09-02T00:00:00Z"
|
||||||
|
"""
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
from ..module_utils.experimental import storage_box_experimental_warning
|
||||||
|
from ..module_utils.hcloud import AnsibleHCloud
|
||||||
|
from ..module_utils.vendor.hcloud import HCloudException
|
||||||
|
from ..module_utils.vendor.hcloud.storage_box_types import BoundStorageBoxType
|
||||||
|
|
||||||
|
|
||||||
|
class AnsibleStorageBoxTypeInfo(AnsibleHCloud):
|
||||||
|
represent = "storage_box_types"
|
||||||
|
|
||||||
|
storage_box_types: list[BoundStorageBoxType] | None = None
|
||||||
|
|
||||||
|
def __init__(self, module: AnsibleModule):
|
||||||
|
storage_box_experimental_warning(module)
|
||||||
|
super().__init__(module)
|
||||||
|
|
||||||
|
def _prepare_result(self):
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for o in self.storage_box_types or []:
|
||||||
|
if o is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
result.append(
|
||||||
|
{
|
||||||
|
"id": o.id,
|
||||||
|
"name": o.name,
|
||||||
|
"description": o.description,
|
||||||
|
"snapshot_limit": o.snapshot_limit,
|
||||||
|
"automatic_snapshot_limit": o.automatic_snapshot_limit,
|
||||||
|
"subaccounts_limit": o.subaccounts_limit,
|
||||||
|
"size": o.size,
|
||||||
|
"deprecation": (
|
||||||
|
{
|
||||||
|
"announced": o.deprecation.announced.isoformat(),
|
||||||
|
"unavailable_after": o.deprecation.unavailable_after.isoformat(),
|
||||||
|
}
|
||||||
|
if o.deprecation is not None
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
try:
|
||||||
|
if (id_ := self.module.params.get("id")) is not None:
|
||||||
|
self.storage_box_types = [self.client.storage_box_types.get_by_id(id_)]
|
||||||
|
elif (name := self.module.params.get("name")) is not None:
|
||||||
|
self.storage_box_types = [self.client.storage_box_types.get_by_name(name)]
|
||||||
|
else:
|
||||||
|
self.storage_box_types = self.client.storage_box_types.get_all()
|
||||||
|
|
||||||
|
except HCloudException as exception:
|
||||||
|
self.fail_json_hcloud(exception)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_module(cls):
|
||||||
|
return AnsibleModule(
|
||||||
|
argument_spec=dict(
|
||||||
|
id={"type": "int"},
|
||||||
|
name={"type": "str"},
|
||||||
|
**super().base_module_arguments(),
|
||||||
|
),
|
||||||
|
supports_check_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleStorageBoxTypeInfo.define_module()
|
||||||
|
o = AnsibleStorageBoxTypeInfo(module)
|
||||||
|
|
||||||
|
o.fetch()
|
||||||
|
result = o.get_result()
|
||||||
|
|
||||||
|
# Legacy return value naming pattern
|
||||||
|
result["hcloud_storage_box_type_info"] = result.pop(o.represent)
|
||||||
|
|
||||||
|
module.exit_json(**result)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -24,3 +24,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,9 @@ hcloud_datacenter_name: hel1-dc2
|
||||||
hcloud_datacenter_id: 3
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
hcloud_network_zone_name: eu-central
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
|
||||||
3
tests/integration/targets/storage_box/aliases
Normal file
3
tests/integration/targets/storage_box/aliases
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/hcloud
|
||||||
|
gather_facts/no
|
||||||
|
azp/group2
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
# Azure Pipelines will configure this value to something similar to
|
||||||
|
# "azp-84824-1-hetzner-2-13-test-2-13-hcloud-3-9-1-default-i"
|
||||||
|
hcloud_prefix: "tests"
|
||||||
|
|
||||||
|
# Used to namespace resources created by concurrent test pipelines/targets
|
||||||
|
hcloud_run_ns: "{{ hcloud_prefix | md5 }}"
|
||||||
|
hcloud_role_ns: "{{ role_name | split('_') | map('batch', 2) | map('first') | flatten() | join() }}"
|
||||||
|
hcloud_ns: "ansible-{{ hcloud_run_ns }}-{{ hcloud_role_ns }}"
|
||||||
|
|
||||||
|
# Used to easily update the server types and images across all our tests.
|
||||||
|
hcloud_server_type_name: cax11
|
||||||
|
hcloud_server_type_id: 45
|
||||||
|
|
||||||
|
hcloud_server_type_upgrade_name: cax21
|
||||||
|
hcloud_server_type_upgrade_id: 93
|
||||||
|
|
||||||
|
hcloud_image_name: debian-12
|
||||||
|
hcloud_image_id: 114690389 # architecture=arm
|
||||||
|
|
||||||
|
hcloud_location_name: hel1
|
||||||
|
hcloud_location_id: 3
|
||||||
|
hcloud_datacenter_name: hel1-dc2
|
||||||
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# 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_storage_box_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_ssh_key_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_storage_box_password: 1-secret-PASSW0RD-=)
|
||||||
3
tests/integration/targets/storage_box/meta/main.yml
Normal file
3
tests/integration/targets/storage_box/meta/main.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_ssh_keypair
|
||||||
5
tests/integration/targets/storage_box/tasks/cleanup.yml
Normal file
5
tests/integration/targets/storage_box/tasks/cleanup.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: Cleanup test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
31
tests/integration/targets/storage_box/tasks/main.yml
Normal file
31
tests/integration/targets/storage_box/tasks/main.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
- name: Check if cleanup.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
register: cleanup_file
|
||||||
|
|
||||||
|
- name: Check if prepare.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
register: prepare_file
|
||||||
|
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
||||||
|
- name: Include prepare tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
when: prepare_file.stat.exists
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
block:
|
||||||
|
- name: Include test tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/test.yml"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
1
tests/integration/targets/storage_box/tasks/prepare.yml
Normal file
1
tests/integration/targets/storage_box/tasks/prepare.yml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
---
|
||||||
247
tests/integration/targets/storage_box/tasks/test.yml
Normal file
247
tests/integration/targets/storage_box/tasks/test.yml
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
---
|
||||||
|
- name: Test missing required parameters
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: present
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify missing required parameters
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
- 'result.msg == "missing required arguments: storage_box_type, location, password"'
|
||||||
|
|
||||||
|
- name: Test create with check mode
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
check_mode: true
|
||||||
|
register: result
|
||||||
|
- name: Verify create with check mode
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: Test create
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
zfs_enabled: false
|
||||||
|
snapshot_plan:
|
||||||
|
max_snapshots: 10
|
||||||
|
hour: 3
|
||||||
|
minute: 30
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
register: result
|
||||||
|
- name: Verify create
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box.id is not none
|
||||||
|
- result.hcloud_storage_box.name == hcloud_storage_box_name
|
||||||
|
- result.hcloud_storage_box.storage_box_type == hcloud_storage_box_type_name
|
||||||
|
- result.hcloud_storage_box.location == hcloud_location_name
|
||||||
|
- result.hcloud_storage_box.labels.key == "value"
|
||||||
|
- result.hcloud_storage_box.delete_protection == false
|
||||||
|
- result.hcloud_storage_box.access_settings.reachable_externally == false
|
||||||
|
- result.hcloud_storage_box.access_settings.samba_enabled == false
|
||||||
|
- result.hcloud_storage_box.access_settings.ssh_enabled == true
|
||||||
|
- result.hcloud_storage_box.access_settings.webdav_enabled == false
|
||||||
|
- result.hcloud_storage_box.access_settings.zfs_enabled == false
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.max_snapshots == 10
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.hour == 3
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.minute == 30
|
||||||
|
- result.hcloud_storage_box.status == "active"
|
||||||
|
- result.hcloud_storage_box.server is not none
|
||||||
|
- result.hcloud_storage_box.system is not none
|
||||||
|
- result.hcloud_storage_box.username is not none
|
||||||
|
- result.hcloud_storage_box.stats.size >= 0
|
||||||
|
- result.hcloud_storage_box.stats.size_data >= 0
|
||||||
|
- result.hcloud_storage_box.stats.size_snapshots >= 0
|
||||||
|
|
||||||
|
- name: Test create idempotency
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
zfs_enabled: false
|
||||||
|
snapshot_plan:
|
||||||
|
max_snapshots: 10
|
||||||
|
hour: 3
|
||||||
|
minute: 30
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
register: result
|
||||||
|
- name: Verify create idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- name: Test update name
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
id: "{{ result.hcloud_storage_box.id }}"
|
||||||
|
name: "{{ hcloud_storage_box_name }}-changed" # Update
|
||||||
|
register: result
|
||||||
|
- name: Verify update name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box.name == hcloud_storage_box_name + "-changed"
|
||||||
|
|
||||||
|
# Ensure snapshot plan was not changed
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.max_snapshots == 10
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.hour == 3
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.minute == 30
|
||||||
|
|
||||||
|
- name: Test update
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
id: "{{ result.hcloud_storage_box.id }}"
|
||||||
|
name: "{{ hcloud_storage_box_name }}" # Update
|
||||||
|
type: "{{ hcloud_storage_box_type_upgrade_name }}" # Update
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings: # Update
|
||||||
|
ssh_enabled: false
|
||||||
|
reachable_externally: true
|
||||||
|
snapshot_plan:
|
||||||
|
max_snapshots: 10
|
||||||
|
hour: 4 # Update
|
||||||
|
minute: 30
|
||||||
|
labels:
|
||||||
|
key: changed # Update
|
||||||
|
delete_protection: true # Update
|
||||||
|
register: result
|
||||||
|
- name: Verify update
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box.id is not none
|
||||||
|
- result.hcloud_storage_box.name == hcloud_storage_box_name
|
||||||
|
- result.hcloud_storage_box.storage_box_type == hcloud_storage_box_type_upgrade_name
|
||||||
|
- result.hcloud_storage_box.location == hcloud_location_name
|
||||||
|
- result.hcloud_storage_box.labels.key == "changed"
|
||||||
|
- result.hcloud_storage_box.delete_protection == true
|
||||||
|
- result.hcloud_storage_box.access_settings.reachable_externally == true
|
||||||
|
- result.hcloud_storage_box.access_settings.samba_enabled == false
|
||||||
|
- result.hcloud_storage_box.access_settings.ssh_enabled == false
|
||||||
|
- result.hcloud_storage_box.access_settings.webdav_enabled == false
|
||||||
|
- result.hcloud_storage_box.access_settings.zfs_enabled == false
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.max_snapshots == 10
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.hour == 4
|
||||||
|
- result.hcloud_storage_box.snapshot_plan.minute == 30
|
||||||
|
|
||||||
|
- name: Test update idempotency
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
id: "{{ result.hcloud_storage_box.id }}"
|
||||||
|
name: "{{ hcloud_storage_box_name }}" # Update
|
||||||
|
type: "{{ hcloud_storage_box_type_upgrade_name }}" # Update
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings: # Update
|
||||||
|
ssh_enabled: false
|
||||||
|
reachable_externally: true
|
||||||
|
snapshot_plan:
|
||||||
|
max_snapshots: 10
|
||||||
|
hour: 4 # Update
|
||||||
|
minute: 30
|
||||||
|
labels:
|
||||||
|
key: changed # Update
|
||||||
|
delete_protection: true # Update
|
||||||
|
register: result
|
||||||
|
- name: Verify update idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- name: Test delete with delete protection
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify delete with delete protection
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
- result.failure.code == "protected"
|
||||||
|
|
||||||
|
- name: Test update delete protection
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
delete_protection: false
|
||||||
|
register: result
|
||||||
|
- name: Verify update delete protection
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box.delete_protection == false
|
||||||
|
|
||||||
|
- name: Test update snapshot plan
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
snapshot_plan: null
|
||||||
|
register: result
|
||||||
|
- name: Verify update snapshot plan
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box.snapshot_plan is none
|
||||||
|
|
||||||
|
- name: Test reset password
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
state: reset_password
|
||||||
|
register: result
|
||||||
|
- name: Verify reset password
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: Create snapshot
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ hcloud_storage_box_name }}"
|
||||||
|
description: test-rollback
|
||||||
|
register: _rollback_snapshot
|
||||||
|
|
||||||
|
- name: Test rollback snapshot
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
snapshot: "{{ _rollback_snapshot.hcloud_storage_box_snapshot.id }}"
|
||||||
|
state: rollback_snapshot
|
||||||
|
register: result
|
||||||
|
- name: Verify rollback snapshot
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: Test delete
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
- name: Verify delete
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box is none
|
||||||
3
tests/integration/targets/storage_box_info/aliases
Normal file
3
tests/integration/targets/storage_box_info/aliases
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/hcloud
|
||||||
|
gather_facts/no
|
||||||
|
azp/group2
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
# Azure Pipelines will configure this value to something similar to
|
||||||
|
# "azp-84824-1-hetzner-2-13-test-2-13-hcloud-3-9-1-default-i"
|
||||||
|
hcloud_prefix: "tests"
|
||||||
|
|
||||||
|
# Used to namespace resources created by concurrent test pipelines/targets
|
||||||
|
hcloud_run_ns: "{{ hcloud_prefix | md5 }}"
|
||||||
|
hcloud_role_ns: "{{ role_name | split('_') | map('batch', 2) | map('first') | flatten() | join() }}"
|
||||||
|
hcloud_ns: "ansible-{{ hcloud_run_ns }}-{{ hcloud_role_ns }}"
|
||||||
|
|
||||||
|
# Used to easily update the server types and images across all our tests.
|
||||||
|
hcloud_server_type_name: cax11
|
||||||
|
hcloud_server_type_id: 45
|
||||||
|
|
||||||
|
hcloud_server_type_upgrade_name: cax21
|
||||||
|
hcloud_server_type_upgrade_id: 93
|
||||||
|
|
||||||
|
hcloud_image_name: debian-12
|
||||||
|
hcloud_image_id: 114690389 # architecture=arm
|
||||||
|
|
||||||
|
hcloud_location_name: hel1
|
||||||
|
hcloud_location_id: 3
|
||||||
|
hcloud_datacenter_name: hel1-dc2
|
||||||
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# 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_storage_box_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_ssh_key_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_storage_box_password: 1-secret-PASSW0RD-=)
|
||||||
3
tests/integration/targets/storage_box_info/meta/main.yml
Normal file
3
tests/integration/targets/storage_box_info/meta/main.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_ssh_keypair
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: Cleanup test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
31
tests/integration/targets/storage_box_info/tasks/main.yml
Normal file
31
tests/integration/targets/storage_box_info/tasks/main.yml
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
- name: Check if cleanup.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
register: cleanup_file
|
||||||
|
|
||||||
|
- name: Check if prepare.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
register: prepare_file
|
||||||
|
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
||||||
|
- name: Include prepare tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
when: prepare_file.stat.exists
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
block:
|
||||||
|
- name: Include test tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/test.yml"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
15
tests/integration/targets/storage_box_info/tasks/prepare.yml
Normal file
15
tests/integration/targets/storage_box_info/tasks/prepare.yml
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
- name: Create test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
zfs_enabled: false
|
||||||
|
labels:
|
||||||
|
key: "{{ hcloud_ns }}"
|
||||||
|
register: test_storage_box
|
||||||
83
tests/integration/targets/storage_box_info/tasks/test.yml
Normal file
83
tests/integration/targets/storage_box_info/tasks/test.yml
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
# Copyright: (c) 2025, 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: Gather hcloud_storage_box_info
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_info
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_info | list | count >= 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_info in check mode
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
check_mode: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_info in check mode
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_info | list | count >= 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_info with label
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
label_selector: key={{ hcloud_ns }}
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_info
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_info | list | count == 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_info with correct id
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
id: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_info with correct id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_info | list | count == 1
|
||||||
|
- result.hcloud_storage_box_info[0].id == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_info[0].name == hcloud_storage_box_name
|
||||||
|
- result.hcloud_storage_box_info[0].storage_box_type == hcloud_storage_box_type_name
|
||||||
|
- result.hcloud_storage_box_info[0].location == hcloud_location_name
|
||||||
|
- result.hcloud_storage_box_info[0].labels.key == hcloud_ns
|
||||||
|
- result.hcloud_storage_box_info[0].delete_protection == false
|
||||||
|
- result.hcloud_storage_box_info[0].access_settings.reachable_externally == false
|
||||||
|
- result.hcloud_storage_box_info[0].access_settings.samba_enabled == false
|
||||||
|
- result.hcloud_storage_box_info[0].access_settings.ssh_enabled == true
|
||||||
|
- result.hcloud_storage_box_info[0].access_settings.webdav_enabled == false
|
||||||
|
- result.hcloud_storage_box_info[0].access_settings.zfs_enabled == false
|
||||||
|
- result.hcloud_storage_box_info[0].status == "active"
|
||||||
|
- result.hcloud_storage_box_info[0].server is not none
|
||||||
|
- result.hcloud_storage_box_info[0].system is not none
|
||||||
|
- result.hcloud_storage_box_info[0].username is not none
|
||||||
|
- result.hcloud_storage_box_info[0].stats.size >= 0
|
||||||
|
- result.hcloud_storage_box_info[0].stats.size_data >= 0
|
||||||
|
- result.hcloud_storage_box_info[0].stats.size_snapshots >= 0
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_info with wrong id
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
id: "{{ test_storage_box.hcloud_storage_box.id }}4321"
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_info with wrong id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_info with correct name
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_info with correct name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_info | list | count == 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_info with wrong name
|
||||||
|
hetzner.hcloud.storage_box_info:
|
||||||
|
name: "{{ hcloud_storage_box_name }}-invalid"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_info with wrong name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_info | list | count == 0
|
||||||
3
tests/integration/targets/storage_box_snapshot/aliases
Normal file
3
tests/integration/targets/storage_box_snapshot/aliases
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/hcloud
|
||||||
|
gather_facts/no
|
||||||
|
azp/group2
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
# Azure Pipelines will configure this value to something similar to
|
||||||
|
# "azp-84824-1-hetzner-2-13-test-2-13-hcloud-3-9-1-default-i"
|
||||||
|
hcloud_prefix: "tests"
|
||||||
|
|
||||||
|
# Used to namespace resources created by concurrent test pipelines/targets
|
||||||
|
hcloud_run_ns: "{{ hcloud_prefix | md5 }}"
|
||||||
|
hcloud_role_ns: "{{ role_name | split('_') | map('batch', 2) | map('first') | flatten() | join() }}"
|
||||||
|
hcloud_ns: "ansible-{{ hcloud_run_ns }}-{{ hcloud_role_ns }}"
|
||||||
|
|
||||||
|
# Used to easily update the server types and images across all our tests.
|
||||||
|
hcloud_server_type_name: cax11
|
||||||
|
hcloud_server_type_id: 45
|
||||||
|
|
||||||
|
hcloud_server_type_upgrade_name: cax21
|
||||||
|
hcloud_server_type_upgrade_id: 93
|
||||||
|
|
||||||
|
hcloud_image_name: debian-12
|
||||||
|
hcloud_image_id: 114690389 # architecture=arm
|
||||||
|
|
||||||
|
hcloud_location_name: hel1
|
||||||
|
hcloud_location_id: 3
|
||||||
|
hcloud_datacenter_name: hel1-dc2
|
||||||
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# 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_storage_box_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_ssh_key_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_storage_box_password: 1-secret-PASSW0RD-=)
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_ssh_keypair
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: Cleanup test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
- name: Check if cleanup.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
register: cleanup_file
|
||||||
|
|
||||||
|
- name: Check if prepare.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
register: prepare_file
|
||||||
|
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
||||||
|
- name: Include prepare tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
when: prepare_file.stat.exists
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
block:
|
||||||
|
- name: Include test tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/test.yml"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
- name: Create test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
reachable_externally: false
|
||||||
|
labels:
|
||||||
|
key: "{{ hcloud_ns }}"
|
||||||
|
register: test_storage_box
|
||||||
119
tests/integration/targets/storage_box_snapshot/tasks/test.yml
Normal file
119
tests/integration/targets/storage_box_snapshot/tasks/test.yml
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
---
|
||||||
|
- name: Test missing required parameters # noqa: args[module]
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify missing required parameters
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
- 'result.msg == "missing required arguments: storage_box"'
|
||||||
|
|
||||||
|
- name: Test create with check mode
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ hcloud_storage_box_name }}"
|
||||||
|
description: migration-1
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
check_mode: true
|
||||||
|
register: result
|
||||||
|
- name: Verify create with check mode
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: Test create
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ hcloud_storage_box_name }}"
|
||||||
|
description: migration-1
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
register: result
|
||||||
|
- name: Verify create
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box_snapshot.storage_box == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_snapshot.id is not none
|
||||||
|
- result.hcloud_storage_box_snapshot.name is not none
|
||||||
|
- result.hcloud_storage_box_snapshot.description == "migration-1"
|
||||||
|
- result.hcloud_storage_box_snapshot.labels.key == "value"
|
||||||
|
- result.hcloud_storage_box_snapshot.is_automatic is false
|
||||||
|
- result.hcloud_storage_box_snapshot.stats.size >= 0
|
||||||
|
- result.hcloud_storage_box_snapshot.stats.size_filesystem >= 0
|
||||||
|
- result.hcloud_storage_box_snapshot.created is not none
|
||||||
|
|
||||||
|
- name: Save Storage Box Snapshot
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
_storage_box_snapshot: "{{ result.hcloud_storage_box_snapshot }}"
|
||||||
|
|
||||||
|
- name: Test create idempotency
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
id: "{{ _storage_box_snapshot.id }}" # Create is not idempotent, only with id or name
|
||||||
|
description: migration-1
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
register: result
|
||||||
|
- name: Verify create idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- name: Test update
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
id: "{{ _storage_box_snapshot.id }}"
|
||||||
|
description: migration-changed # Update
|
||||||
|
labels:
|
||||||
|
key: changed # Update
|
||||||
|
register: result
|
||||||
|
- name: Verify update
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box_snapshot.storage_box == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_snapshot.id is not none
|
||||||
|
- result.hcloud_storage_box_snapshot.name is not none
|
||||||
|
- result.hcloud_storage_box_snapshot.description == "migration-changed"
|
||||||
|
- result.hcloud_storage_box_snapshot.labels.key == "changed"
|
||||||
|
- result.hcloud_storage_box_snapshot.is_automatic is false
|
||||||
|
- result.hcloud_storage_box_snapshot.stats.size >= 0
|
||||||
|
- result.hcloud_storage_box_snapshot.stats.size_filesystem >= 0
|
||||||
|
- result.hcloud_storage_box_snapshot.created is not none
|
||||||
|
|
||||||
|
- name: Test update idempotency
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.name }}"
|
||||||
|
name: "{{ _storage_box_snapshot.name }}"
|
||||||
|
description: migration-changed # Update
|
||||||
|
labels:
|
||||||
|
key: changed # Update
|
||||||
|
register: result
|
||||||
|
- name: Verify update idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- name: Test delete
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.name }}"
|
||||||
|
name: "{{ _storage_box_snapshot.name }}"
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
- name: Verify delete
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box_snapshot is none
|
||||||
|
|
||||||
|
- name: Test delete idempotency
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.name }}"
|
||||||
|
name: "{{ _storage_box_snapshot.name }}"
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
- name: Verify delete idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/hcloud
|
||||||
|
gather_facts/no
|
||||||
|
azp/group2
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
# Azure Pipelines will configure this value to something similar to
|
||||||
|
# "azp-84824-1-hetzner-2-13-test-2-13-hcloud-3-9-1-default-i"
|
||||||
|
hcloud_prefix: "tests"
|
||||||
|
|
||||||
|
# Used to namespace resources created by concurrent test pipelines/targets
|
||||||
|
hcloud_run_ns: "{{ hcloud_prefix | md5 }}"
|
||||||
|
hcloud_role_ns: "{{ role_name | split('_') | map('batch', 2) | map('first') | flatten() | join() }}"
|
||||||
|
hcloud_ns: "ansible-{{ hcloud_run_ns }}-{{ hcloud_role_ns }}"
|
||||||
|
|
||||||
|
# Used to easily update the server types and images across all our tests.
|
||||||
|
hcloud_server_type_name: cax11
|
||||||
|
hcloud_server_type_id: 45
|
||||||
|
|
||||||
|
hcloud_server_type_upgrade_name: cax21
|
||||||
|
hcloud_server_type_upgrade_id: 93
|
||||||
|
|
||||||
|
hcloud_image_name: debian-12
|
||||||
|
hcloud_image_id: 114690389 # architecture=arm
|
||||||
|
|
||||||
|
hcloud_location_name: hel1
|
||||||
|
hcloud_location_id: 3
|
||||||
|
hcloud_datacenter_name: hel1-dc2
|
||||||
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# 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_storage_box_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_ssh_key_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_storage_box_password: 1-secret-PASSW0RD-=)
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_ssh_keypair
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: Cleanup test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
- name: Check if cleanup.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
register: cleanup_file
|
||||||
|
|
||||||
|
- name: Check if prepare.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
register: prepare_file
|
||||||
|
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
||||||
|
- name: Include prepare tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
when: prepare_file.stat.exists
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
block:
|
||||||
|
- name: Include test tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/test.yml"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
- name: Create test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
reachable_externally: false
|
||||||
|
labels:
|
||||||
|
key: "{{ hcloud_ns }}"
|
||||||
|
register: test_storage_box
|
||||||
|
|
||||||
|
- name: Create test_storage_box_snapshot1
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
description: snapshot1
|
||||||
|
labels:
|
||||||
|
key: "{{ hcloud_ns }}"
|
||||||
|
register: test_storage_box_snapshot1
|
||||||
|
|
||||||
|
- name: Create test_storage_box_snapshot2
|
||||||
|
hetzner.hcloud.storage_box_snapshot:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
register: test_storage_box_snapshot2
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Copyright: (c) 2025, 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: Gather hcloud_storage_box_snapshot_info
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_snapshot_info
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_snapshot_info | list | count == 2
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_snapshot_info in check mode
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
check_mode: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_snapshot_info in check mode
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_snapshot_info | list | count == 2
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_snapshot_info with label
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
label_selector: "key={{ hcloud_ns }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_snapshot_info
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_snapshot_info | list | count == 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_snapshot_info with correct id
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
id: "{{ test_storage_box_snapshot1.hcloud_storage_box_snapshot.id }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_snapshot_info with correct id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_snapshot_info | list | count == 1
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].storage_box == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].id is not none
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].name is not none
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].description == "snapshot1"
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].labels.key == hcloud_ns
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].is_automatic is false
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].stats.size >= 0
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].stats.size_filesystem >= 0
|
||||||
|
- result.hcloud_storage_box_snapshot_info[0].created is not none
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_snapshot_info with wrong id
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
id: "{{ test_storage_box_snapshot1.hcloud_storage_box_snapshot.id }}4321"
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_snapshot_info with wrong id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_snapshot_info with correct name
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: "{{ test_storage_box_snapshot1.hcloud_storage_box_snapshot.name }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_snapshot_info with correct name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_snapshot_info | list | count == 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_snapshot_info with wrong name
|
||||||
|
hetzner.hcloud.storage_box_snapshot_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: "{{ test_storage_box_snapshot1.hcloud_storage_box_snapshot.name }}-invalid"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_snapshot_info with wrong name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_snapshot_info | list | count == 0
|
||||||
3
tests/integration/targets/storage_box_subaccount/aliases
Normal file
3
tests/integration/targets/storage_box_subaccount/aliases
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/hcloud
|
||||||
|
gather_facts/no
|
||||||
|
azp/group2
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
# Azure Pipelines will configure this value to something similar to
|
||||||
|
# "azp-84824-1-hetzner-2-13-test-2-13-hcloud-3-9-1-default-i"
|
||||||
|
hcloud_prefix: "tests"
|
||||||
|
|
||||||
|
# Used to namespace resources created by concurrent test pipelines/targets
|
||||||
|
hcloud_run_ns: "{{ hcloud_prefix | md5 }}"
|
||||||
|
hcloud_role_ns: "{{ role_name | split('_') | map('batch', 2) | map('first') | flatten() | join() }}"
|
||||||
|
hcloud_ns: "ansible-{{ hcloud_run_ns }}-{{ hcloud_role_ns }}"
|
||||||
|
|
||||||
|
# Used to easily update the server types and images across all our tests.
|
||||||
|
hcloud_server_type_name: cax11
|
||||||
|
hcloud_server_type_id: 45
|
||||||
|
|
||||||
|
hcloud_server_type_upgrade_name: cax21
|
||||||
|
hcloud_server_type_upgrade_id: 93
|
||||||
|
|
||||||
|
hcloud_image_name: debian-12
|
||||||
|
hcloud_image_id: 114690389 # architecture=arm
|
||||||
|
|
||||||
|
hcloud_location_name: hel1
|
||||||
|
hcloud_location_id: 3
|
||||||
|
hcloud_datacenter_name: hel1-dc2
|
||||||
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# 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_storage_box_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_ssh_key_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_storage_box_password: 1-secret-PASSW0RD-=)
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_ssh_keypair
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: Cleanup test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
- name: Check if cleanup.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
register: cleanup_file
|
||||||
|
|
||||||
|
- name: Check if prepare.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
register: prepare_file
|
||||||
|
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
||||||
|
- name: Include prepare tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
when: prepare_file.stat.exists
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
block:
|
||||||
|
- name: Include test tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/test.yml"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
- name: Create test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
reachable_externally: false
|
||||||
|
labels:
|
||||||
|
key: "{{ hcloud_ns }}"
|
||||||
|
register: test_storage_box
|
||||||
190
tests/integration/targets/storage_box_subaccount/tasks/test.yml
Normal file
190
tests/integration/targets/storage_box_subaccount/tasks/test.yml
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
---
|
||||||
|
- name: Test missing required parameters # noqa: args[module]
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ hcloud_storage_box_name }}"
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify missing required parameters
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
- 'result.msg == "one of the following is required: id, name"'
|
||||||
|
|
||||||
|
- name: Test create with check mode
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ hcloud_storage_box_name }}"
|
||||||
|
name: subaccount1
|
||||||
|
description: backups from subaccount1
|
||||||
|
home_directory: backups/subaccount1
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
readonly: false
|
||||||
|
check_mode: true
|
||||||
|
register: result
|
||||||
|
- name: Verify create with check mode
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: Test create
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ hcloud_storage_box_name }}"
|
||||||
|
name: subaccount1
|
||||||
|
description: backups from subaccount1
|
||||||
|
home_directory: backups/subaccount1
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
readonly: false
|
||||||
|
register: result
|
||||||
|
- name: Verify create
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box_subaccount.storage_box == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_subaccount.id is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.name == "subaccount1"
|
||||||
|
- result.hcloud_storage_box_subaccount.description == "backups from subaccount1"
|
||||||
|
- result.hcloud_storage_box_subaccount.home_directory == "backups/subaccount1"
|
||||||
|
- result.hcloud_storage_box_subaccount.username is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.server is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.labels.key == "value"
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.reachable_externally == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.samba_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.ssh_enabled == true
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.webdav_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.readonly == false
|
||||||
|
- result.hcloud_storage_box_subaccount.created is not none
|
||||||
|
|
||||||
|
- name: Test create idempotency
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount1
|
||||||
|
description: backups from subaccount1
|
||||||
|
home_directory: backups/subaccount1
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
labels:
|
||||||
|
key: value
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
readonly: false
|
||||||
|
register: result
|
||||||
|
- name: Verify create idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- name: Test update
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount1
|
||||||
|
description: backups from subaccount2 # Update
|
||||||
|
home_directory: backups/subaccount2 # Update
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
labels:
|
||||||
|
key: changed # Update
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
readonly: true # Update
|
||||||
|
register: result
|
||||||
|
- name: Verify update
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box_subaccount.storage_box == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_subaccount.id is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.name == "subaccount1"
|
||||||
|
- result.hcloud_storage_box_subaccount.description == "backups from subaccount2"
|
||||||
|
- result.hcloud_storage_box_subaccount.home_directory == "backups/subaccount2"
|
||||||
|
- result.hcloud_storage_box_subaccount.username is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.server is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.labels.key == "changed"
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.reachable_externally == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.samba_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.ssh_enabled == true
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.webdav_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.readonly == true
|
||||||
|
- result.hcloud_storage_box_subaccount.created is not none
|
||||||
|
|
||||||
|
- name: Test update idempotency
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount1
|
||||||
|
description: backups from subaccount2 # Update
|
||||||
|
home_directory: backups/subaccount2 # Update
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
labels:
|
||||||
|
key: changed # Update
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
readonly: true # Update
|
||||||
|
register: result
|
||||||
|
- name: Verify update idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
|
- name: Test update name
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
id: "{{ result.hcloud_storage_box_subaccount.id }}"
|
||||||
|
name: subaccount2
|
||||||
|
register: result
|
||||||
|
- name: Verify update
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box_subaccount.storage_box == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_subaccount.id is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.name == "subaccount2" # Update
|
||||||
|
- result.hcloud_storage_box_subaccount.description == "backups from subaccount2"
|
||||||
|
- result.hcloud_storage_box_subaccount.home_directory == "backups/subaccount2"
|
||||||
|
- result.hcloud_storage_box_subaccount.username is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.server is not none
|
||||||
|
- result.hcloud_storage_box_subaccount.labels.key == "changed"
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.reachable_externally == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.samba_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.ssh_enabled == true
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.webdav_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount.access_settings.readonly == true
|
||||||
|
- result.hcloud_storage_box_subaccount.created is not none
|
||||||
|
|
||||||
|
- name: Test reset password
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount2
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
state: reset_password
|
||||||
|
register: result
|
||||||
|
- name: Verify reset password
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
|
||||||
|
- name: Test delete
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount2
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
- name: Verify delete
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.hcloud_storage_box_subaccount is none
|
||||||
|
|
||||||
|
- name: Test delete idempotency
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount2
|
||||||
|
state: absent
|
||||||
|
register: result
|
||||||
|
- name: Verify delete idempotency
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/hcloud
|
||||||
|
gather_facts/no
|
||||||
|
azp/group2
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
# Azure Pipelines will configure this value to something similar to
|
||||||
|
# "azp-84824-1-hetzner-2-13-test-2-13-hcloud-3-9-1-default-i"
|
||||||
|
hcloud_prefix: "tests"
|
||||||
|
|
||||||
|
# Used to namespace resources created by concurrent test pipelines/targets
|
||||||
|
hcloud_run_ns: "{{ hcloud_prefix | md5 }}"
|
||||||
|
hcloud_role_ns: "{{ role_name | split('_') | map('batch', 2) | map('first') | flatten() | join() }}"
|
||||||
|
hcloud_ns: "ansible-{{ hcloud_run_ns }}-{{ hcloud_role_ns }}"
|
||||||
|
|
||||||
|
# Used to easily update the server types and images across all our tests.
|
||||||
|
hcloud_server_type_name: cax11
|
||||||
|
hcloud_server_type_id: 45
|
||||||
|
|
||||||
|
hcloud_server_type_upgrade_name: cax21
|
||||||
|
hcloud_server_type_upgrade_id: 93
|
||||||
|
|
||||||
|
hcloud_image_name: debian-12
|
||||||
|
hcloud_image_id: 114690389 # architecture=arm
|
||||||
|
|
||||||
|
hcloud_location_name: hel1
|
||||||
|
hcloud_location_id: 3
|
||||||
|
hcloud_datacenter_name: hel1-dc2
|
||||||
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# 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_storage_box_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_ssh_key_name: "{{ hcloud_ns }}"
|
||||||
|
hcloud_storage_box_password: 1-secret-PASSW0RD-=)
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
dependencies:
|
||||||
|
- setup_ssh_keypair
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
- name: Cleanup test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
state: absent
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
- name: Check if cleanup.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
register: cleanup_file
|
||||||
|
|
||||||
|
- name: Check if prepare.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
register: prepare_file
|
||||||
|
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
||||||
|
- name: Include prepare tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
when: prepare_file.stat.exists
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
block:
|
||||||
|
- name: Include test tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/test.yml"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
- name: Create test_storage_box
|
||||||
|
hetzner.hcloud.storage_box:
|
||||||
|
name: "{{ hcloud_storage_box_name }}"
|
||||||
|
type: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
location: "{{ hcloud_location_name }}"
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
ssh_keys:
|
||||||
|
- "{{ test_ssh_keypair.public_key }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
reachable_externally: false
|
||||||
|
labels:
|
||||||
|
key: "{{ hcloud_ns }}"
|
||||||
|
register: test_storage_box
|
||||||
|
|
||||||
|
- name: Create test_storage_box_subaccount1
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount1
|
||||||
|
description: backups from subaccount1
|
||||||
|
home_directory: backups/subaccount1
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
access_settings:
|
||||||
|
ssh_enabled: true
|
||||||
|
readonly: false
|
||||||
|
labels:
|
||||||
|
key: "{{ hcloud_ns }}"
|
||||||
|
register: test_storage_box_subaccount1
|
||||||
|
|
||||||
|
- name: Create test_storage_box_subaccount2
|
||||||
|
hetzner.hcloud.storage_box_subaccount:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: subaccount2
|
||||||
|
home_directory: backups/subaccount2
|
||||||
|
password: "{{ hcloud_storage_box_password }}"
|
||||||
|
register: test_storage_box_subaccount2
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
# Copyright: (c) 2025, 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: Gather hcloud_storage_box_subaccount_info
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_subaccount_info
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_subaccount_info | list | count == 2
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_subaccount_info in check mode
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
check_mode: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_subaccount_info in check mode
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_subaccount_info | list | count == 2
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_subaccount_info with label
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
label_selector: "key={{ hcloud_ns }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_subaccount_info
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_subaccount_info | list | count == 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_subaccount_info with correct id
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
id: "{{ test_storage_box_subaccount1.hcloud_storage_box_subaccount.id }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_subaccount_info with correct id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_subaccount_info | list | count == 1
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].storage_box == test_storage_box.hcloud_storage_box.id
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].id is not none
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].name == "subaccount1"
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].home_directory == "backups/subaccount1"
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].username is not none
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].server is not none
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].description == "backups from subaccount1"
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].labels.key == hcloud_ns
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].access_settings.reachable_externally == false
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].access_settings.samba_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].access_settings.ssh_enabled == true
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].access_settings.webdav_enabled == false
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].access_settings.readonly == false
|
||||||
|
- result.hcloud_storage_box_subaccount_info[0].created is not none
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_subaccount_info with wrong id
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
id: "{{ test_storage_box_subaccount1.hcloud_storage_box_subaccount.id }}4321"
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_subaccount_info with wrong id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_subaccount_info with correct name
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: "{{ test_storage_box_subaccount1.hcloud_storage_box_subaccount.name }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_subaccount_info with correct name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_subaccount_info | list | count == 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_subaccount_info with wrong name
|
||||||
|
hetzner.hcloud.storage_box_subaccount_info:
|
||||||
|
storage_box: "{{ test_storage_box.hcloud_storage_box.id }}"
|
||||||
|
name: "{{ test_storage_box_subaccount1.hcloud_storage_box_subaccount.name }}-invalid"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_subaccount_info with wrong name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_subaccount_info | list | count == 0
|
||||||
3
tests/integration/targets/storage_box_type_info/aliases
Normal file
3
tests/integration/targets/storage_box_type_info/aliases
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/hcloud
|
||||||
|
gather_facts/no
|
||||||
|
azp/group2
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
# Azure Pipelines will configure this value to something similar to
|
||||||
|
# "azp-84824-1-hetzner-2-13-test-2-13-hcloud-3-9-1-default-i"
|
||||||
|
hcloud_prefix: "tests"
|
||||||
|
|
||||||
|
# Used to namespace resources created by concurrent test pipelines/targets
|
||||||
|
hcloud_run_ns: "{{ hcloud_prefix | md5 }}"
|
||||||
|
hcloud_role_ns: "{{ role_name | split('_') | map('batch', 2) | map('first') | flatten() | join() }}"
|
||||||
|
hcloud_ns: "ansible-{{ hcloud_run_ns }}-{{ hcloud_role_ns }}"
|
||||||
|
|
||||||
|
# Used to easily update the server types and images across all our tests.
|
||||||
|
hcloud_server_type_name: cax11
|
||||||
|
hcloud_server_type_id: 45
|
||||||
|
|
||||||
|
hcloud_server_type_upgrade_name: cax21
|
||||||
|
hcloud_server_type_upgrade_id: 93
|
||||||
|
|
||||||
|
hcloud_image_name: debian-12
|
||||||
|
hcloud_image_id: 114690389 # architecture=arm
|
||||||
|
|
||||||
|
hcloud_location_name: hel1
|
||||||
|
hcloud_location_id: 3
|
||||||
|
hcloud_datacenter_name: hel1-dc2
|
||||||
|
hcloud_datacenter_id: 3
|
||||||
|
|
||||||
|
hcloud_network_zone_name: eu-central
|
||||||
|
|
||||||
|
hcloud_storage_box_type_name: bx11
|
||||||
|
hcloud_storage_box_type_id: 1333
|
||||||
|
|
||||||
|
hcloud_storage_box_type_upgrade_name: bx21
|
||||||
|
hcloud_storage_box_type_upgrade_id: 1334
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Copyright: (c) 2025, 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)
|
||||||
|
---
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#
|
||||||
|
# DO NOT EDIT THIS FILE! Please edit the files in tests/integration/common instead.
|
||||||
|
#
|
||||||
|
---
|
||||||
|
- name: Check if cleanup.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
register: cleanup_file
|
||||||
|
|
||||||
|
- name: Check if prepare.yml exists
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
register: prepare_file
|
||||||
|
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
||||||
|
- name: Include prepare tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/prepare.yml"
|
||||||
|
when: prepare_file.stat.exists
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
block:
|
||||||
|
- name: Include test tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/test.yml"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Include cleanup tasks
|
||||||
|
ansible.builtin.include_tasks: "{{ role_path }}/tasks/cleanup.yml"
|
||||||
|
when: cleanup_file.stat.exists
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
# Copyright: (c) 2025, 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: Gather hcloud_storage_box_type_info
|
||||||
|
hetzner.hcloud.storage_box_type_info:
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_type_info
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_type_info | list | count >= 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_type_info in check mode
|
||||||
|
hetzner.hcloud.storage_box_type_info:
|
||||||
|
check_mode: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_type_info in check mode
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_type_info | list | count >= 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_type_info with correct id
|
||||||
|
hetzner.hcloud.storage_box_type_info:
|
||||||
|
id: "{{ hcloud_storage_box_type_id }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_type_info with correct id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_type_info | list | count == 1
|
||||||
|
- result.hcloud_storage_box_type_info[0].id == hcloud_storage_box_type_id
|
||||||
|
- result.hcloud_storage_box_type_info[0].name == hcloud_storage_box_type_name
|
||||||
|
- result.hcloud_storage_box_type_info[0].description == "BX11"
|
||||||
|
- result.hcloud_storage_box_type_info[0].snapshot_limit == 10
|
||||||
|
- result.hcloud_storage_box_type_info[0].automatic_snapshot_limit == 10
|
||||||
|
- result.hcloud_storage_box_type_info[0].subaccounts_limit == 100
|
||||||
|
- result.hcloud_storage_box_type_info[0].size == 1099511627776
|
||||||
|
- result.hcloud_storage_box_type_info[0].deprecation is none
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_type_info with wrong id
|
||||||
|
hetzner.hcloud.storage_box_type_info:
|
||||||
|
id: "{{ hcloud_storage_box_type_id }}4321"
|
||||||
|
ignore_errors: true
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_type_info with wrong id
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result is failed
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_type_info with correct name
|
||||||
|
hetzner.hcloud.storage_box_type_info:
|
||||||
|
name: "{{ hcloud_storage_box_type_name }}"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_type_info with correct name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_type_info | list | count == 1
|
||||||
|
|
||||||
|
- name: Gather hcloud_storage_box_type_info with wrong name
|
||||||
|
hetzner.hcloud.storage_box_type_info:
|
||||||
|
name: "{{ hcloud_storage_box_type_name }}-invalid"
|
||||||
|
register: result
|
||||||
|
- name: Verify hcloud_storage_box_type_info with wrong name
|
||||||
|
ansible.builtin.assert:
|
||||||
|
that:
|
||||||
|
- result.hcloud_storage_box_type_info | list | count == 0
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue