|
8 | 8 | from ..storage_box_types import BoundStorageBoxType, StorageBoxType |
9 | 9 | from .domain import ( |
10 | 10 | CreateStorageBoxResponse, |
| 11 | + CreateStorageBoxSnapshotResponse, |
11 | 12 | DeleteStorageBoxResponse, |
| 13 | + DeleteStorageBoxSnapshotResponse, |
12 | 14 | StorageBox, |
13 | 15 | StorageBoxAccessSettings, |
14 | 16 | StorageBoxFoldersResponse, |
15 | 17 | StorageBoxSnapshot, |
16 | 18 | StorageBoxSnapshotPlan, |
| 19 | + StorageBoxSnapshotStats, |
17 | 20 | StorageBoxStats, |
18 | 21 | ) |
19 | 22 |
|
@@ -105,11 +108,42 @@ def get_actions( |
105 | 108 | # TODO: implement bound methods |
106 | 109 |
|
107 | 110 |
|
| 111 | +class BoundStorageBoxSnapshot(BoundModelBase, StorageBoxSnapshot): |
| 112 | + _client: StorageBoxesClient |
| 113 | + |
| 114 | + model = StorageBoxSnapshot |
| 115 | + |
| 116 | + def __init__( |
| 117 | + self, |
| 118 | + client: StorageBoxesClient, |
| 119 | + data: dict[str, Any], |
| 120 | + complete: bool = True, |
| 121 | + ): |
| 122 | + raw = data.get("storage_box") |
| 123 | + if raw is not None: |
| 124 | + data["storage_box"] = BoundStorageBox( |
| 125 | + client, data={"id": raw}, complete=False |
| 126 | + ) |
| 127 | + |
| 128 | + raw = data.get("stats") |
| 129 | + if raw is not None: |
| 130 | + data["stats"] = StorageBoxSnapshotStats.from_dict(raw) |
| 131 | + |
| 132 | + super().__init__(client, data, complete) |
| 133 | + |
| 134 | + # TODO: implement bound methods |
| 135 | + |
| 136 | + |
108 | 137 | class StorageBoxesPageResult(NamedTuple): |
109 | 138 | storage_boxes: list[BoundStorageBox] |
110 | 139 | meta: Meta |
111 | 140 |
|
112 | 141 |
|
| 142 | +class StorageBoxSnapshotsPageResult(NamedTuple): |
| 143 | + snapshots: list[BoundStorageBoxSnapshot] |
| 144 | + meta: Meta |
| 145 | + |
| 146 | + |
113 | 147 | class StorageBoxesClient(ResourceClientBase): |
114 | 148 | """ |
115 | 149 | A client for the Storage Boxes API. |
@@ -556,3 +590,198 @@ def enable_snapshot_plan( |
556 | 590 | json=data, |
557 | 591 | ) |
558 | 592 | return BoundAction(self._parent.actions, response["action"]) |
| 593 | + |
| 594 | + # Snapshots |
| 595 | + ########################################################################### |
| 596 | + |
| 597 | + def get_snapshot_by_id( |
| 598 | + self, |
| 599 | + storage_box: StorageBox | BoundStorageBox, |
| 600 | + id: int, |
| 601 | + ) -> BoundStorageBoxSnapshot: |
| 602 | + """ |
| 603 | + Returns a single Snapshot from a Storage Box. |
| 604 | +
|
| 605 | + See https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots-get-a-snapshot |
| 606 | +
|
| 607 | + :param storage_box: Storage Box to get the Snapshot from. |
| 608 | + :param id: ID of the Snapshot. |
| 609 | + """ |
| 610 | + response = self._client.request( |
| 611 | + method="GET", |
| 612 | + url=f"{self._base_url}/{storage_box.id}/snapshots/{id}", |
| 613 | + ) |
| 614 | + return BoundStorageBoxSnapshot(self, response["snapshot"]) |
| 615 | + |
| 616 | + def get_snapshot_by_name( |
| 617 | + self, |
| 618 | + storage_box: StorageBox | BoundStorageBox, |
| 619 | + name: str, |
| 620 | + ) -> BoundStorageBoxSnapshot: |
| 621 | + """ |
| 622 | + Returns a single Snapshot from a Storage Box. |
| 623 | +
|
| 624 | + See https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots-list-snapshots |
| 625 | +
|
| 626 | + :param storage_box: Storage Box to get the Snapshot from. |
| 627 | + :param name: Name of the Snapshot. |
| 628 | + """ |
| 629 | + return self._get_first_by(self.get_snapshot_list, storage_box, name=name) |
| 630 | + |
| 631 | + def get_snapshot_list( |
| 632 | + self, |
| 633 | + storage_box: StorageBox | BoundStorageBox, |
| 634 | + *, |
| 635 | + name: str | None = None, |
| 636 | + is_automatic: bool | None = None, |
| 637 | + label_selector: str | None = None, |
| 638 | + sort: list[str] | None = None, |
| 639 | + ) -> StorageBoxSnapshotsPageResult: |
| 640 | + """ |
| 641 | + Returns all Snapshots for a Storage Box. |
| 642 | +
|
| 643 | + See https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots-list-snapshots |
| 644 | +
|
| 645 | + :param storage_box: Storage Box to get the Snapshots from. |
| 646 | + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. |
| 647 | + :param is_automatic: Filter wether the snapshot was made by a Snapshot Plan. |
| 648 | + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. |
| 649 | + :param sort: Sort resources by field and direction. |
| 650 | + """ |
| 651 | + params: dict[str, Any] = {} |
| 652 | + if name is not None: |
| 653 | + params["name"] = name |
| 654 | + if is_automatic is not None: |
| 655 | + params["is_automatic"] = is_automatic |
| 656 | + if label_selector is not None: |
| 657 | + params["label_selector"] = label_selector |
| 658 | + if sort is not None: |
| 659 | + params["sort"] = sort |
| 660 | + |
| 661 | + response = self._client.request( |
| 662 | + method="GET", |
| 663 | + url=f"{self._base_url}/{storage_box.id}/snapshots", |
| 664 | + params=params, |
| 665 | + ) |
| 666 | + return StorageBoxSnapshotsPageResult( |
| 667 | + snapshots=[ |
| 668 | + BoundStorageBoxSnapshot(self, item) for item in response["snapshots"] |
| 669 | + ], |
| 670 | + meta=Meta.parse_meta(response), |
| 671 | + ) |
| 672 | + |
| 673 | + def get_snapshot_all( |
| 674 | + self, |
| 675 | + storage_box: StorageBox | BoundStorageBox, |
| 676 | + *, |
| 677 | + name: str | None = None, |
| 678 | + is_automatic: bool | None = None, |
| 679 | + label_selector: str | None = None, |
| 680 | + sort: list[str] | None = None, |
| 681 | + ) -> list[BoundStorageBoxSnapshot]: |
| 682 | + """ |
| 683 | + Returns all Snapshots for a Storage Box. |
| 684 | +
|
| 685 | + See https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots-list-snapshots |
| 686 | +
|
| 687 | + :param storage_box: Storage Box to get the Snapshots from. |
| 688 | + :param name: Filter resources by their name. The response will only contain the resources matching exactly the specified name. |
| 689 | + :param is_automatic: Filter wether the snapshot was made by a Snapshot Plan. |
| 690 | + :param label_selector: Filter resources by labels. The response will only contain resources matching the label selector. |
| 691 | + :param sort: Sort resources by field and direction. |
| 692 | + """ |
| 693 | + # The endpoint does not have pagination, forward to the list method. |
| 694 | + result, _ = self.get_snapshot_list( |
| 695 | + storage_box, |
| 696 | + name=name, |
| 697 | + is_automatic=is_automatic, |
| 698 | + label_selector=label_selector, |
| 699 | + sort=sort, |
| 700 | + ) |
| 701 | + return result |
| 702 | + |
| 703 | + def create_snapshot( |
| 704 | + self, |
| 705 | + storage_box: StorageBox | BoundStorageBox, |
| 706 | + *, |
| 707 | + description: str | None = None, |
| 708 | + labels: dict[str, str] | None = None, |
| 709 | + ) -> CreateStorageBoxSnapshotResponse: |
| 710 | + """ |
| 711 | + Creates a Snapshot of the Storage Box. |
| 712 | +
|
| 713 | + See https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots-create-a-snapshot |
| 714 | +
|
| 715 | + :param storage_box: Storage Box to create a Snapshot from. |
| 716 | + :param description: Description of the Snapshot. |
| 717 | + :param labels: User-defined labels (key/value pairs) for the Resource. |
| 718 | + """ |
| 719 | + data: dict[str, Any] = {} |
| 720 | + if description is not None: |
| 721 | + data["description"] = description |
| 722 | + if labels is not None: |
| 723 | + data["labels"] = labels |
| 724 | + |
| 725 | + response = self._client.request( |
| 726 | + method="POST", |
| 727 | + url=f"{self._base_url}/{storage_box.id}/snapshots", |
| 728 | + json=data, |
| 729 | + ) |
| 730 | + return CreateStorageBoxSnapshotResponse( |
| 731 | + snapshot=BoundStorageBoxSnapshot(self, response["snapshot"]), |
| 732 | + action=BoundAction(self._parent.actions, response["action"]), |
| 733 | + ) |
| 734 | + |
| 735 | + def update_snapshot( |
| 736 | + self, |
| 737 | + snapshot: StorageBoxSnapshot | BoundStorageBoxSnapshot, |
| 738 | + *, |
| 739 | + description: str | None = None, |
| 740 | + labels: dict[str, str] | None = None, |
| 741 | + ) -> BoundStorageBoxSnapshot: |
| 742 | + """ |
| 743 | + Updates a Storage Box Snapshot. |
| 744 | +
|
| 745 | + See https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots-update-a-snapshot |
| 746 | +
|
| 747 | + :param snapshot: Storage Box Snapshot to update. |
| 748 | + :param description: Description of the Snapshot. |
| 749 | + :param labels: User-defined labels (key/value pairs) for the Resource. |
| 750 | + """ |
| 751 | + if snapshot.storage_box is None: |
| 752 | + raise ValueError("snapshot storage_box property is none") |
| 753 | + |
| 754 | + data: dict[str, Any] = {} |
| 755 | + if description is not None: |
| 756 | + data["description"] = description |
| 757 | + if labels is not None: |
| 758 | + data["labels"] = labels |
| 759 | + |
| 760 | + response = self._client.request( |
| 761 | + method="PUT", |
| 762 | + url=f"{self._base_url}/{snapshot.storage_box.id}/snapshots/{snapshot.id}", |
| 763 | + json=data, |
| 764 | + ) |
| 765 | + return BoundStorageBoxSnapshot(self, response["snapshot"]) |
| 766 | + |
| 767 | + def delete_snapshot( |
| 768 | + self, |
| 769 | + snapshot: StorageBoxSnapshot | BoundStorageBoxSnapshot, |
| 770 | + ) -> DeleteStorageBoxSnapshotResponse: |
| 771 | + """ |
| 772 | + Deletes a Storage Box Snapshot. |
| 773 | +
|
| 774 | + See https://docs.hetzner.cloud/reference/hetzner#storage-box-snapshots-delete-a-snapshot |
| 775 | +
|
| 776 | + :param snapshot: Storage Box Snapshot to delete. |
| 777 | + """ |
| 778 | + if snapshot.storage_box is None: |
| 779 | + raise ValueError("snapshot storage_box property is none") |
| 780 | + |
| 781 | + response = self._client.request( |
| 782 | + method="DELETE", |
| 783 | + url=f"{self._base_url}/{snapshot.storage_box.id}/snapshots/{snapshot.id}", |
| 784 | + ) |
| 785 | + return DeleteStorageBoxSnapshotResponse( |
| 786 | + action=BoundAction(self._parent.actions, response["action"]), |
| 787 | + ) |
0 commit comments