from __future__ import annotations from typing import Optional from . import base_api import json class Snapshot(base_api.BaseApi): """Class for interacting with Snapshot APIs. This class implements APIs to manage snapshots. There is no documentation for these APIs, so the implementation is based on network inspection. Examples -------- List snapshots for a share: >>> from synology_api import snapshot >>> ss = snapshot.Snapshot('IP', 'PORT', 'USER', 'PASSWORD') >>> resp = ss.list_snapshots('share_name') >>> print(resp) Create a snapshot for a share: >>> resp = ss.create_snapshot('share_name') >>> print(resp) Delete snapshots for a share: >>> resp = ss.delete_snapshots('share_name', ['snapshot_name']) >>> print(resp) Set attributes for a snapshot: >>> resp = ss.set_snapshot_attr('share_name', 'snapshot_name', description='new description', lock=True) >>> print(resp) """ def list_snapshots(self, share_name: str, attribute_filter: list[str] = [], additional_attribute: list[str] = [], offset: int = 0, limit: int = -1) -> dict[str, object] | str: """List snapshots for a share. Parameters ---------- share_name : str Name of the share to list snapshots for attribute_filter : list[str], optional List of attributes filter to apply. Defaults to [] (no filter). Each attribute filter is a string in the format of "attr==value" or "attr=value" and optionally prefixed with "!" to negate the filter. The following are examples of valid attribute filters: - ["!hide==true", "desc==abc"] # hide is not true and desc is exactly abc - ["desc=abc"] # desc has abc in it additional_attribute : list[str], optional List of snapshot attributes whose values are included in the response. Defaults to [] (only time is returned). Note that not all attributes are available via API. The following are confirmed to work: - desc - lock - worm_lock - schedule_snapshot offset : int, optional Offset to start listing from. Defaults to 0. limit : int, optional Number of snapshots to return. Defaults to -1 (all). Returns ------- dict[str, object] | str API response if successful, error message if not Example: { "data": { "snapshots": [ { "desc": "", "lock": true, "schedule_snapshot": false, "time": "GMT+09-2023.09.11-23.23.40", "worm_lock": true, "worm_lock_begin": "1694442321", "worm_lock_day": "1", "worm_lock_end": "1694528721" } ], "total": 1 }, "success": true } """ api_name = 'SYNO.Core.Share.Snapshot' info = self.gen_list[api_name] api_path = info['path'] req_param = {'version': '2', 'method': 'list', 'name': share_name, 'filter': json.dumps({"attr": attribute_filter}), 'additional': json.dumps(additional_attribute), 'offset': offset, 'limit': limit} return self.request_data(api_name, api_path, req_param) def create_snapshot(self, share_name: str, description: str = "", lock: bool = False, immutable: bool = False, immutable_days: int = 7, ) -> dict[str, object] | str: """Create a snapshot for a share. Parameters ---------- share_name : str Name of the share to create a snapshot for description : str, optional Description of the snapshot. Defaults to "". lock : bool, optional Whether to lock the snapshot. Defaults to False. immutable : bool, optional Whether to make the snapshot immutable. Defaults to False. immutable_days : int, optional Number of days to make the snapshot immutable for. Defaults to 7. Must be greater than 0. Mandatory if immutable is True. Returns ------- dict[str, object] | str API response if successful, error message if not Example: { "data": "GMT+09-2023.09.12-00.33.20", "success": true } """ api_name = 'SYNO.Core.Share.Snapshot' info = self.gen_list[api_name] api_path = info['path'] snapinfo = { "desc": description, "lock": lock, } if immutable == True: snapinfo['worm_lock'] = True if immutable_days < 1: return "immutable_days must be greater than 0" snapinfo['worm_lock_day'] = immutable_days req_param = {'version': '1', 'method': 'create', 'snapinfo': json.dumps(snapinfo), 'name': share_name} return self.request_data(api_name, api_path, req_param) def delete_snapshots(self, share_name: str, snapshots: list[str] ) -> dict[str, object] | str: """Delete snapshots for a share. Parameters ---------- share_name : str Name of the share to delete snapshots for snapshots : list[str] List of snapshots to delete Returns ------- dict[str, object] | str API response if successful, error message if not Example: { "success": true } """ api_name = 'SYNO.Core.Share.Snapshot' info = self.gen_list[api_name] api_path = info['path'] req_param = {'version': '1', 'method': 'delete', 'name': share_name, 'snapshots': json.dumps(snapshots)} return self.request_data(api_name, api_path, req_param) def set_snapshot_attr(self, share_name: str, snapshot: str, description: Optional[str] = None, lock: Optional[bool] = None, immutable: Optional[bool] = None, immutable_days: Optional[int] = None ) -> dict[str, object] | str: """Set attributes for a snapshot. Parameters ---------- share_name : str Name of the share to set attributes for snapshot : str Name of the snapshot to set attributes for description : str, optional Description of the snapshot. Defaults to None (no change). lock : bool, optional Whether to lock the snapshot. Defaults to None (no change). immutable : bool, optional Whether to make the snapshot immutable. Defaults to None (no change). immutable_days : int, optional Number of days to make the snapshot immutable for. Defaults to None (no change). Must be greater than 0. Mandatory if immutable is True. Returns ------- dict[str, object] | str API response if successful, error message if not Example: { "success": true } """ api_name = 'SYNO.Core.Share.Snapshot' info = self.gen_list[api_name] api_path = info['path'] snapinfo = {} if description is not None: snapinfo['desc'] = description if lock is not None: snapinfo['lock'] = lock if immutable is not None: if immutable == False: return "immutable cannot be set to False" if immutable_days is None: return "immutable_days must be specified if immutable is True" if immutable_days < 1: return "immutable_days must be greater than 0" snapinfo['worm_lock'] = True snapinfo['worm_lock_day'] = immutable_days req_param = {'version': '1', 'method': 'set', 'snapinfo': json.dumps(snapinfo), 'name': share_name, 'snapshot': snapshot} return self.request_data(api_name, api_path, req_param)