From 2b56408eaca224ec708aa50c70dbe12bc2875814 Mon Sep 17 00:00:00 2001 From: Quentin POLLET Date: Thu, 30 Apr 2020 19:21:52 +0200 Subject: [PATCH 1/3] Fix Storage volume_disk_temp_[X] for SHR disks redundancy --- synology_dsm/api/storage/storage.py | 12 +- tests/__init__.py | 19 +- tests/api_data/dsm_5/__init__.py | 2 +- .../dsm_5/storage/const_5_storage_storage.py | 2 +- tests/api_data/dsm_6/__init__.py | 2 +- tests/api_data/dsm_6/dsm/const_6_dsm_info.py | 19 +- .../dsm_6/storage/const_6_storage_storage.py | 459 +++++++++++++++++- tests/test_synology_dsm.py | 70 ++- 8 files changed, 571 insertions(+), 14 deletions(-) diff --git a/synology_dsm/api/storage/storage.py b/synology_dsm/api/storage/storage.py index 304eff21..05ed01df 100644 --- a/synology_dsm/api/storage/storage.py +++ b/synology_dsm/api/storage/storage.py @@ -147,9 +147,19 @@ def _get_disks_for_volume(self, volume_id): """Returns a list of disk for a specific volume.""" disks = [] for pool in self.storage_pools: - if pool["deploy_path"] == volume_id: + + if pool.get("deploy_path") == volume_id: + # RAID disk redundancy for disk_id in pool["disks"]: disks.append(self._get_disk(disk_id)) + + if pool.get("pool_child"): + # SHR disk redundancy + for pool_child in pool.get("pool_child"): + if pool_child["id"] == volume_id: + for disk_id in pool["disks"]: + disks.append(self._get_disk(disk_id)) + return disks def disk_name(self, disk_id): diff --git a/tests/__init__.py b/tests/__init__.py index fe4cb1ad..4fa0d482 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -23,7 +23,8 @@ DSM_6_AUTH_LOGIN_2SA_OTP, DSM_6_DSM_INFORMATION, DSM_6_CORE_UTILIZATION, - DSM_6_STORAGE_STORAGE, + DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, + DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL, ) from .api_data.dsm_5 import ( DSM_5_API_INFO, @@ -32,7 +33,7 @@ DSM_5_AUTH_LOGIN_2SA_OTP, DSM_5_DSM_INFORMATION, DSM_5_CORE_UTILIZATION, - DSM_5_STORAGE_STORAGE, + DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL, ) API_SWITCHER = { @@ -43,7 +44,9 @@ "AUTH_LOGIN_2SA_OTP": DSM_5_AUTH_LOGIN_2SA_OTP, "DSM_INFORMATION": DSM_5_DSM_INFORMATION, "CORE_UTILIZATION": DSM_5_CORE_UTILIZATION, - "STORAGE_STORAGE": DSM_5_STORAGE_STORAGE, + "STORAGE_STORAGE": { + "RAID":DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL, + }, }, 6: { "API_INFO": DSM_6_API_INFO, @@ -52,7 +55,10 @@ "AUTH_LOGIN_2SA_OTP": DSM_6_AUTH_LOGIN_2SA_OTP, "DSM_INFORMATION": DSM_6_DSM_INFORMATION, "CORE_UTILIZATION": DSM_6_CORE_UTILIZATION, - "STORAGE_STORAGE": DSM_6_STORAGE_STORAGE, + "STORAGE_STORAGE": { + "RAID": DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL, + "SHR": DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, + } }, } @@ -97,7 +103,8 @@ def __init__( debugmode, ) - self.dsm_version = 6 + self.dsm_version = 6 # 5 or 6 + self.disks_redundancy = "RAID" # RAID or SHR def _execute_request(self, method, url, **kwargs): url += urlencode(kwargs["params"]) @@ -163,7 +170,7 @@ def _execute_request(self, method, url, **kwargs): return API_SWITCHER[self.dsm_version]["CORE_UTILIZATION"] if SynoStorage.API_KEY in url: - return API_SWITCHER[self.dsm_version]["STORAGE_STORAGE"] + return API_SWITCHER[self.dsm_version]["STORAGE_STORAGE"][self.disks_redundancy] if ( "SYNO.FileStation.Upload" in url diff --git a/tests/api_data/dsm_5/__init__.py b/tests/api_data/dsm_5/__init__.py index 0b26b299..4809e9e5 100644 --- a/tests/api_data/dsm_5/__init__.py +++ b/tests/api_data/dsm_5/__init__.py @@ -7,4 +7,4 @@ ) from .core.const_5_core_utilization import DSM_5_CORE_UTILIZATION from .dsm.const_5_dsm_info import DSM_5_DSM_INFORMATION -from .storage.const_5_storage_storage import DSM_5_STORAGE_STORAGE +from .storage.const_5_storage_storage import DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL diff --git a/tests/api_data/dsm_5/storage/const_5_storage_storage.py b/tests/api_data/dsm_5/storage/const_5_storage_storage.py index b4b03c0f..674fed66 100644 --- a/tests/api_data/dsm_5/storage/const_5_storage_storage.py +++ b/tests/api_data/dsm_5/storage/const_5_storage_storage.py @@ -2,7 +2,7 @@ """DSM 5 SYNO.Storage.CGI.Storage data.""" from tests.const import UNIQUE_KEY -DSM_5_STORAGE_STORAGE = { +DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL = { "disks": [ {"id": "test_disk"}, { diff --git a/tests/api_data/dsm_6/__init__.py b/tests/api_data/dsm_6/__init__.py index a4b828f1..0058fa14 100644 --- a/tests/api_data/dsm_6/__init__.py +++ b/tests/api_data/dsm_6/__init__.py @@ -7,4 +7,4 @@ ) from .core.const_6_core_utilization import DSM_6_CORE_UTILIZATION from .dsm.const_6_dsm_info import DSM_6_DSM_INFORMATION -from .storage.const_6_storage_storage import DSM_6_STORAGE_STORAGE +from .storage.const_6_storage_storage import DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL diff --git a/tests/api_data/dsm_6/dsm/const_6_dsm_info.py b/tests/api_data/dsm_6/dsm/const_6_dsm_info.py index 2d0675ce..c20191a0 100644 --- a/tests/api_data/dsm_6/dsm/const_6_dsm_info.py +++ b/tests/api_data/dsm_6/dsm/const_6_dsm_info.py @@ -1,8 +1,23 @@ # -*- coding: utf-8 -*- """DSM 6 SYNO.DSM.Info data.""" +DSM_6_DSM_INFORMATION_DS213_PLUS = { + "data": { + "codepage": "enu", + "model": "DS213+", + "ram": 512, + "serial": "XXXXXXXXXXX", + "temperature": 30, + "temperature_warn": False, + "time": "Thu Apr 30 14:57:35 2020", + "uptime": 3258607, + "version": "24922", + "version_string": "DSM 6.2.2-24922 Update 4", + }, + "success": True, +} -DSM_6_DSM_INFORMATION = { +DSM_6_DSM_INFORMATION_DS918_PLUS = { "data": { "codepage": "fre", "model": "DS918+", @@ -17,3 +32,5 @@ }, "success": True, } + +DSM_6_DSM_INFORMATION = DSM_6_DSM_INFORMATION_DS918_PLUS diff --git a/tests/api_data/dsm_6/storage/const_6_storage_storage.py b/tests/api_data/dsm_6/storage/const_6_storage_storage.py index 8dee870b..94ff8645 100644 --- a/tests/api_data/dsm_6/storage/const_6_storage_storage.py +++ b/tests/api_data/dsm_6/storage/const_6_storage_storage.py @@ -2,7 +2,464 @@ """DSM 6 SYNO.Storage.CGI.Storage data.""" from tests.const import UNIQUE_KEY -DSM_6_STORAGE_STORAGE = { +DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS = { + "data": { + "disks": [ + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS213+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sda", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 510, + "exceed_bad_sector_thr": False, + "firm": "80.00A80", + "has_system": True, + "id": "sda", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 1", + "model": "WD30E", + "name": "Drive 1", + "num_id": 1, + "order": 1, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-xxxxx", + "size_total": "3000592982016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 29, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS213+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdb", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 424, + "exceed_bad_sector_thr": False, + "firm": "1AN10003", + "has_system": True, + "id": "sdb", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 2", + "model": "HD20xxx", + "name": "Drive 2", + "num_id": 2, + "order": 2, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "S1Uxxxxxxxxxxxx", + "size_total": "2000398934016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 30, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_2", + "vendor": "SAMSUNG ", + }, + ], + "env": { + "batchtask": {"max_task": 64, "remain_task": 64}, + "bay_number": "2", + "data_scrubbing": {"sche_enabled": "0", "sche_status": "disabled"}, + "ebox": [], + "fs_acting": False, + "isSyncSysPartition": False, + "is_space_actioning": False, + "isns": {"address": "", "enabled": False}, + "isns_server": "", + "max_fs_bytes": "17592181850112", + "max_fs_bytes_high_end": "219902325555200", + "model_name": "DS213+", + "ram_enough_for_fs_high_end": False, + "ram_size": 0, + "ram_size_required": 32, + "showpooltab": True, + "status": {"system_crashed": False, "system_need_repair": False}, + "support": {"ebox": True, "raid_cross": False, "sysdef": True}, + "support_fit_fs_limit": False, + "unique_key": UNIQUE_KEY, + "volume_full_critical": 0.05, + "volume_full_warning": 0.1, + }, + "hotSpareConf": {"cross_repair": True, "disable_repair": []}, + "hotSpares": [], + "iscsiLuns": [], + "iscsiTargets": [], + "ports": [], + "storagePools": [ + { + "cacheStatus": "", + "can_do": { + "delete": True, + "expand_by_disk": 1, + "migrate": {"to_shr2": 3}, + }, + "container": "internal", + "desc": "Diskgroep 2", + "device_type": "shr_without_disk_protect", + "disk_failure_number": 0, + "disks": ["sdb"], + "drive_type": 0, + "id": "reuse_2", + "is_actioning": False, + "is_scheduled": False, + "is_writable": True, + "last_done_time": 0, + "limited_disk_number": 12, + "maximal_disk_size": "0", + "minimal_disk_size": "2000292986880", + "next_schedule_time": 0, + "num_id": 2, + "pool_child": [{"id": "volume_2", "size": {"total": "1995435933696"}}], + "pool_path": "reuse_2", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "multiple", + "raids": [ + { + "designedDiskCount": 1, + "devices": [{"id": "sdb", "slot": 0, "status": "normal"}], + "hasParity": False, + "minDevSize": "2000292986880", + "normalDevCount": 1, + "raidPath": "/dev/md3", + "raidStatus": 1, + "spares": [], + } + ], + "scrubbingStatus": "has_not_run_yet", + "size": {"total": "1995448516608", "used": "1995448516608"}, + "space_path": "/dev/vg2", + "spares": [], + "status": "normal", + "suggestions": [], + "timebackup": False, + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "remove": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + }, + { + "cacheStatus": "", + "can_do": { + "delete": True, + "expand_by_disk": 1, + "migrate": {"to_shr2": 3}, + }, + "container": "internal", + "desc": "Diskgroep1", + "device_type": "shr_without_disk_protect", + "disk_failure_number": 0, + "disks": ["sda"], + "drive_type": 0, + "id": "reuse_1", + "is_actioning": False, + "is_scheduled": False, + "is_writable": True, + "last_done_time": 0, + "limited_disk_number": 12, + "maximal_disk_size": "0", + "minimal_disk_size": "3000487034880", + "next_schedule_time": 0, + "num_id": 1, + "pool_child": [{"id": "volume_1", "size": {"total": "2995630637056"}}], + "pool_path": "reuse_1", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "multiple", + "raids": [ + { + "designedDiskCount": 1, + "devices": [{"id": "sda", "slot": 0, "status": "normal"}], + "hasParity": False, + "minDevSize": "3000487034880", + "normalDevCount": 1, + "raidPath": "/dev/md2", + "raidStatus": 1, + "spares": [], + } + ], + "scrubbingStatus": "has_not_run_yet", + "size": {"total": "2995643219968", "used": "2995643219968"}, + "space_path": "/dev/vg1", + "spares": [], + "status": "normal", + "suggestions": [], + "timebackup": False, + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "remove": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + }, + ], + "volumes": [ + { + "atime_checked": False, + "atime_opt": "relatime", + "cacheStatus": "", + "can_do": {"delete": True}, + "container": "internal", + "desc": "Volume_Diskgroep2", + "device_type": "shr_without_disk_protect", + "disk_failure_number": 0, + "disks": [], + "drive_type": 0, + "eppool_used": "0", + "exist_alive_vdsm": False, + "fs_type": "ext4", + "id": "volume_2", + "is_acting": False, + "is_actioning": False, + "is_inode_full": False, + "is_scheduled": False, + "is_writable": True, + "last_done_time": 0, + "limited_disk_number": 12, + "max_fs_size": "17577577283584", + "next_schedule_time": 0, + "num_id": 2, + "pool_path": "reuse_2", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "multiple", + "scrubbingStatus": "", + "size": { + "free_inode": "121689412", + "total": "1964124495872", + "total_device": "1995435933696", + "total_inode": "121798656", + "used": "1684179374080", + }, + "ssd_trim": {"support": "not support"}, + "status": "normal", + "suggestions": [], + "timebackup": False, + "used_by_gluster": False, + "vol_path": "/volume2", + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "remove": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + }, + { + "atime_checked": False, + "atime_opt": "relatime", + "cacheStatus": "", + "can_do": {"delete": True}, + "container": "internal", + "desc": "Volume_Diskgroep1", + "device_type": "shr_without_disk_protect", + "disk_failure_number": 0, + "disks": [], + "drive_type": 0, + "eppool_used": "0", + "exist_alive_vdsm": False, + "fs_type": "ext4", + "id": "volume_1", + "is_acting": False, + "is_actioning": False, + "is_inode_full": False, + "is_scheduled": False, + "is_writable": True, + "last_done_time": 0, + "limited_disk_number": 12, + "max_fs_size": "17581339574272", + "next_schedule_time": 0, + "num_id": 1, + "pool_path": "reuse_1", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "multiple", + "scrubbingStatus": "", + "size": { + "free_inode": "182794183", + "total": "2948623499264", + "total_device": "2995630637056", + "total_inode": "182845440", + "used": "2710796488704", + }, + "ssd_trim": {"support": "not support"}, + "status": "normal", + "suggestions": [{"str": "volume_usage_suggestion", "type": "warning"}], + "timebackup": False, + "used_by_gluster": False, + "vol_path": "/volume1", + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "remove": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + }, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + }, + ], + }, + "success": True, +} + +DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL = { "data": { "disks": [ {"id": "test_disk"}, diff --git a/tests/test_synology_dsm.py b/tests/test_synology_dsm.py index 0fc32346..858202d6 100644 --- a/tests/test_synology_dsm.py +++ b/tests/test_synology_dsm.py @@ -239,8 +239,8 @@ def test_storage(self): assert self.api.storage.storage_pools assert self.api.storage.volumes - def test_storage_volumes(self): - """Test storage volumes.""" + def test_storage_raid_volumes(self): + """Test RAID storage volumes.""" # Basics assert self.api.storage.volumes_ids for volume_id in self.api.storage.volumes_ids: @@ -289,6 +289,72 @@ def test_storage_volumes(self): assert self.api.storage.volume_disk_temp_avg("test_volume") is None assert self.api.storage.volume_disk_temp_max("test_volume") is None + + def test_storage_shr_volumes(self): + """Test SHR storage volumes.""" + api = SynologyDSMMock( + VALID_HOST, VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL + ) + api.disks_redundancy = "SHR" + + # Basics + assert api.storage.volumes_ids + for volume_id in api.storage.volumes_ids: + if volume_id == "test_volume": + continue + assert api.storage.volume_status(volume_id) + assert api.storage.volume_device_type(volume_id) + assert api.storage.volume_size_total(volume_id) + assert api.storage.volume_size_total(volume_id, False) + assert api.storage.volume_size_used(volume_id) + assert api.storage.volume_size_used(volume_id, False) + assert api.storage.volume_percentage_used(volume_id) + assert api.storage.volume_disk_temp_avg(volume_id) + assert api.storage.volume_disk_temp_max(volume_id) + + # Existing volume + assert api.storage.volume_status("volume_1") == "normal" + assert api.storage.volume_device_type("volume_1") == "shr_without_disk_protect" + assert api.storage.volume_size_total("volume_1") == "2.7Tb" + assert api.storage.volume_size_total("volume_1", False) == 2948623499264 + assert api.storage.volume_size_used("volume_1") == "2.5Tb" + assert api.storage.volume_size_used("volume_1", False) == 2710796488704 + assert api.storage.volume_percentage_used("volume_1") == 91.9 + assert api.storage.volume_disk_temp_avg("volume_1") == 29.0 + assert api.storage.volume_disk_temp_max("volume_1") == 29 + + assert api.storage.volume_status("volume_2") == "normal" + assert api.storage.volume_device_type("volume_2") == "shr_without_disk_protect" + assert api.storage.volume_size_total("volume_2") == "1.8Tb" + assert api.storage.volume_size_total("volume_2", False) == 1964124495872 + assert api.storage.volume_size_used("volume_2") == "1.5Tb" + assert api.storage.volume_size_used("volume_2", False) == 1684179374080 + assert api.storage.volume_percentage_used("volume_2") == 85.7 + assert api.storage.volume_disk_temp_avg("volume_2") == 30.0 + assert api.storage.volume_disk_temp_max("volume_2") == 30 + + # Non existing volume + assert not api.storage.volume_status("not_a_volume") + assert not api.storage.volume_device_type("not_a_volume") + assert not api.storage.volume_size_total("not_a_volume") + assert not api.storage.volume_size_total("not_a_volume", False) + assert not api.storage.volume_size_used("not_a_volume") + assert not api.storage.volume_size_used("not_a_volume", False) + assert not api.storage.volume_percentage_used("not_a_volume") + assert not api.storage.volume_disk_temp_avg("not_a_volume") + assert not api.storage.volume_disk_temp_max("not_a_volume") + + # Test volume + assert api.storage.volume_status("test_volume") is None + assert api.storage.volume_device_type("test_volume") is None + assert api.storage.volume_size_total("test_volume") is None + assert api.storage.volume_size_total("test_volume", False) is None + assert api.storage.volume_size_used("test_volume") is None + assert api.storage.volume_size_used("test_volume", False) is None + assert api.storage.volume_percentage_used("test_volume") is None + assert api.storage.volume_disk_temp_avg("test_volume") is None + assert api.storage.volume_disk_temp_max("test_volume") is None + def test_storage_disks(self): """Test storage disks.""" # Basics From a40135802ff3ca402075f98da24c93378c111abd Mon Sep 17 00:00:00 2001 From: Quentin POLLET Date: Thu, 30 Apr 2020 19:28:47 +0200 Subject: [PATCH 2/3] Fix pylint & black --- tests/__init__.py | 14 +++++----- tests/api_data/dsm_5/__init__.py | 4 ++- tests/api_data/dsm_6/__init__.py | 5 +++- tests/test_synology_dsm.py | 48 ++++++++++++++++---------------- tests/test_synology_dsm_5.py | 47 ++++++++++++++++--------------- 5 files changed, 62 insertions(+), 56 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 4fa0d482..2547ff5c 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -44,9 +44,7 @@ "AUTH_LOGIN_2SA_OTP": DSM_5_AUTH_LOGIN_2SA_OTP, "DSM_INFORMATION": DSM_5_DSM_INFORMATION, "CORE_UTILIZATION": DSM_5_CORE_UTILIZATION, - "STORAGE_STORAGE": { - "RAID":DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL, - }, + "STORAGE_STORAGE": {"RAID": DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL,}, }, 6: { "API_INFO": DSM_6_API_INFO, @@ -58,7 +56,7 @@ "STORAGE_STORAGE": { "RAID": DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL, "SHR": DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, - } + }, }, } @@ -103,8 +101,8 @@ def __init__( debugmode, ) - self.dsm_version = 6 # 5 or 6 - self.disks_redundancy = "RAID" # RAID or SHR + self.dsm_version = 6 # 5 or 6 + self.disks_redundancy = "RAID" # RAID or SHR def _execute_request(self, method, url, **kwargs): url += urlencode(kwargs["params"]) @@ -170,7 +168,9 @@ def _execute_request(self, method, url, **kwargs): return API_SWITCHER[self.dsm_version]["CORE_UTILIZATION"] if SynoStorage.API_KEY in url: - return API_SWITCHER[self.dsm_version]["STORAGE_STORAGE"][self.disks_redundancy] + return API_SWITCHER[self.dsm_version]["STORAGE_STORAGE"][ + self.disks_redundancy + ] if ( "SYNO.FileStation.Upload" in url diff --git a/tests/api_data/dsm_5/__init__.py b/tests/api_data/dsm_5/__init__.py index 4809e9e5..e4a94980 100644 --- a/tests/api_data/dsm_5/__init__.py +++ b/tests/api_data/dsm_5/__init__.py @@ -7,4 +7,6 @@ ) from .core.const_5_core_utilization import DSM_5_CORE_UTILIZATION from .dsm.const_5_dsm_info import DSM_5_DSM_INFORMATION -from .storage.const_5_storage_storage import DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL +from .storage.const_5_storage_storage import ( + DSM_5_STORAGE_STORAGE_DS410J_RAID5_4DISKS_1VOL, +) diff --git a/tests/api_data/dsm_6/__init__.py b/tests/api_data/dsm_6/__init__.py index 0058fa14..3d420c4a 100644 --- a/tests/api_data/dsm_6/__init__.py +++ b/tests/api_data/dsm_6/__init__.py @@ -7,4 +7,7 @@ ) from .core.const_6_core_utilization import DSM_6_CORE_UTILIZATION from .dsm.const_6_dsm_info import DSM_6_DSM_INFORMATION -from .storage.const_6_storage_storage import DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL +from .storage.const_6_storage_storage import ( + DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, + DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL, +) diff --git a/tests/test_synology_dsm.py b/tests/test_synology_dsm.py index 858202d6..bc03fa38 100644 --- a/tests/test_synology_dsm.py +++ b/tests/test_synology_dsm.py @@ -23,7 +23,8 @@ ) from .const import SESSION_ID, DEVICE_TOKEN, SYNO_TOKEN - +# pylint: disable=no-self-use +# pylint: disable=protected-access class TestSynologyDSM(TestCase): """SynologyDSM test cases.""" @@ -37,11 +38,11 @@ def setUp(self): def test_init(self): """Test init.""" assert self.api.username - assert self.api._base_url # pylint: disable=protected-access + assert self.api._base_url assert not self.api.apis.get(SynologyDSMMock.API_AUTH) - assert not self.api._session_id # pylint: disable=protected-access + assert not self.api._session_id - def test_connection_failed(self): # pylint: disable=no-self-use + def test_connection_failed(self): """Test failed connection.""" api = SynologyDSMMock( "no_internet", VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL @@ -49,46 +50,46 @@ def test_connection_failed(self): # pylint: disable=no-self-use with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock("host", VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL) with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock(VALID_HOST, 0, VALID_USER, VALID_PASSWORD, VALID_SSL) with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock(VALID_HOST, VALID_PORT, VALID_USER, VALID_PASSWORD, False) with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id def test_login(self): """Test login.""" assert self.api.login() assert self.api.apis.get(SynologyDSMMock.API_AUTH) - assert self.api._session_id == SESSION_ID # pylint: disable=protected-access - assert self.api._syno_token == SYNO_TOKEN # pylint: disable=protected-access + assert self.api._session_id == SESSION_ID + assert self.api._syno_token == SYNO_TOKEN - def test_login_failed(self): # pylint: disable=no-self-use + def test_login_failed(self): """Test failed login.""" api = SynologyDSMMock(VALID_HOST, VALID_PORT, "user", VALID_PASSWORD, VALID_SSL) with self.assertRaises(SynologyDSMLoginInvalidException): assert not api.login() assert api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock(VALID_HOST, VALID_PORT, VALID_USER, "pass", VALID_SSL) with self.assertRaises(SynologyDSMLoginInvalidException): assert not api.login() assert api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id def test_login_2sa(self): """Test login with 2SA.""" @@ -99,9 +100,9 @@ def test_login_2sa(self): api.login() api.login(VALID_OTP) - assert api._session_id == SESSION_ID # pylint: disable=protected-access - assert api._syno_token == SYNO_TOKEN # pylint: disable=protected-access - assert api._device_token == DEVICE_TOKEN # pylint: disable=protected-access + assert api._session_id == SESSION_ID + assert api._syno_token == SYNO_TOKEN + assert api._device_token == DEVICE_TOKEN assert api.device_token == DEVICE_TOKEN def test_login_2sa_new_session(self): # pylint: disable=no-self-use @@ -116,9 +117,9 @@ def test_login_2sa_new_session(self): # pylint: disable=no-self-use ) assert api.login() - assert api._session_id == SESSION_ID # pylint: disable=protected-access - assert api._syno_token == SYNO_TOKEN # pylint: disable=protected-access - assert api._device_token == DEVICE_TOKEN # pylint: disable=protected-access + assert api._session_id == SESSION_ID + assert api._syno_token == SYNO_TOKEN + assert api._device_token == DEVICE_TOKEN assert api.device_token == DEVICE_TOKEN def test_login_2sa_failed(self): @@ -131,9 +132,9 @@ def test_login_2sa_failed(self): with self.assertRaises(SynologyDSMLogin2SAFailedException): api.login(888888) - assert api._session_id is None # pylint: disable=protected-access - assert api._syno_token is None # pylint: disable=protected-access - assert api._device_token is None # pylint: disable=protected-access + assert api._session_id is None + assert api._syno_token is None + assert api._device_token is None def test_request_get(self): """Test get request.""" @@ -289,7 +290,6 @@ def test_storage_raid_volumes(self): assert self.api.storage.volume_disk_temp_avg("test_volume") is None assert self.api.storage.volume_disk_temp_max("test_volume") is None - def test_storage_shr_volumes(self): """Test SHR storage volumes.""" api = SynologyDSMMock( @@ -322,7 +322,7 @@ def test_storage_shr_volumes(self): assert api.storage.volume_percentage_used("volume_1") == 91.9 assert api.storage.volume_disk_temp_avg("volume_1") == 29.0 assert api.storage.volume_disk_temp_max("volume_1") == 29 - + assert api.storage.volume_status("volume_2") == "normal" assert api.storage.volume_device_type("volume_2") == "shr_without_disk_protect" assert api.storage.volume_size_total("volume_2") == "1.8Tb" diff --git a/tests/test_synology_dsm_5.py b/tests/test_synology_dsm_5.py index 9aef1dbc..bf1fe7b2 100644 --- a/tests/test_synology_dsm_5.py +++ b/tests/test_synology_dsm_5.py @@ -23,7 +23,8 @@ ) from .const import SESSION_ID, DEVICE_TOKEN - +# pylint: disable=no-self-use +# pylint: disable=protected-access class TestSynologyDSM(TestCase): """SynologyDSM test cases.""" @@ -38,11 +39,11 @@ def setUp(self): def test_init(self): """Test init.""" assert self.api.username - assert self.api._base_url # pylint: disable=protected-access + assert self.api._base_url assert not self.api.apis.get(SynologyDSMMock.API_AUTH) - assert not self.api._session_id # pylint: disable=protected-access + assert not self.api._session_id - def test_connection_failed(self): # pylint: disable=no-self-use + def test_connection_failed(self): """Test failed connection.""" api = SynologyDSMMock( "no_internet", VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL @@ -51,51 +52,51 @@ def test_connection_failed(self): # pylint: disable=no-self-use with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock("host", VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL) api.dsm_version = 5 with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock(VALID_HOST, 0, VALID_USER, VALID_PASSWORD, VALID_SSL) api.dsm_version = 5 with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock(VALID_HOST, VALID_PORT, VALID_USER, VALID_PASSWORD, False) api.dsm_version = 5 with self.assertRaises(SynologyDSMRequestException): assert not api.login() assert not api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id def test_login(self): """Test login.""" assert self.api.login() assert self.api.apis.get(SynologyDSMMock.API_AUTH) - assert self.api._session_id == SESSION_ID # pylint: disable=protected-access - assert self.api._syno_token is None # pylint: disable=protected-access + assert self.api._session_id == SESSION_ID + assert self.api._syno_token is None - def test_login_failed(self): # pylint: disable=no-self-use + def test_login_failed(self): """Test failed login.""" api = SynologyDSMMock(VALID_HOST, VALID_PORT, "user", VALID_PASSWORD, VALID_SSL) api.dsm_version = 5 with self.assertRaises(SynologyDSMLoginInvalidException): assert not api.login() assert api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id api = SynologyDSMMock(VALID_HOST, VALID_PORT, VALID_USER, "pass", VALID_SSL) api.dsm_version = 5 with self.assertRaises(SynologyDSMLoginInvalidException): assert not api.login() assert api.apis.get(SynologyDSMMock.API_AUTH) - assert not api._session_id # pylint: disable=protected-access + assert not api._session_id def test_login_2sa(self): """Test login with 2SA.""" @@ -107,12 +108,12 @@ def test_login_2sa(self): api.login() api.login(VALID_OTP) - assert api._session_id == SESSION_ID # pylint: disable=protected-access - assert api._syno_token is None # pylint: disable=protected-access - assert api._device_token == DEVICE_TOKEN # pylint: disable=protected-access + assert api._session_id == SESSION_ID + assert api._syno_token is None + assert api._device_token == DEVICE_TOKEN assert api.device_token == DEVICE_TOKEN - def test_login_2sa_new_session(self): # pylint: disable=no-self-use + def test_login_2sa_new_session(self): """Test login with 2SA and a new session with granted device.""" api = SynologyDSMMock( VALID_HOST, @@ -125,9 +126,9 @@ def test_login_2sa_new_session(self): # pylint: disable=no-self-use api.dsm_version = 5 assert api.login() - assert api._session_id == SESSION_ID # pylint: disable=protected-access - assert api._syno_token is None # pylint: disable=protected-access - assert api._device_token == DEVICE_TOKEN # pylint: disable=protected-access + assert api._session_id == SESSION_ID + assert api._syno_token is None + assert api._device_token == DEVICE_TOKEN assert api.device_token == DEVICE_TOKEN def test_login_2sa_failed(self): @@ -141,9 +142,9 @@ def test_login_2sa_failed(self): with self.assertRaises(SynologyDSMLogin2SAFailedException): api.login(888888) - assert api._session_id is None # pylint: disable=protected-access - assert api._syno_token is None # pylint: disable=protected-access - assert api._device_token is None # pylint: disable=protected-access + assert api._session_id is None + assert api._syno_token is None + assert api._device_token is None def test_request_get(self): """Test get request.""" From 60735ab95fddd2bd2a451b45463a430107f755f6 Mon Sep 17 00:00:00 2001 From: Quentin POLLET Date: Fri, 1 May 2020 13:48:59 +0200 Subject: [PATCH 3/3] Add SHR2 redundancy tests --- tests/__init__.py | 8 +- tests/api_data/dsm_6/__init__.py | 2 + .../dsm_6/storage/const_6_storage_storage.py | 1356 +++++++++++++++++ tests/test_synology_dsm.py | 64 +- 4 files changed, 1427 insertions(+), 3 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 2547ff5c..f029b0ff 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -25,6 +25,8 @@ DSM_6_CORE_UTILIZATION, DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL, + DSM_6_STORAGE_STORAGE_DS1819_PLUS_SHR2_8DISKS_1VOL, + DSM_6_STORAGE_STORAGE_DS1515_PLUS_SHR2_10DISKS_1VOL_WITH_EXPANSION, ) from .api_data.dsm_5 import ( DSM_5_API_INFO, @@ -55,7 +57,9 @@ "CORE_UTILIZATION": DSM_6_CORE_UTILIZATION, "STORAGE_STORAGE": { "RAID": DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL, - "SHR": DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, + "SHR1": DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, + "SHR2": DSM_6_STORAGE_STORAGE_DS1819_PLUS_SHR2_8DISKS_1VOL, + "SHR2_EXPANSION": DSM_6_STORAGE_STORAGE_DS1515_PLUS_SHR2_10DISKS_1VOL_WITH_EXPANSION, }, }, } @@ -102,7 +106,7 @@ def __init__( ) self.dsm_version = 6 # 5 or 6 - self.disks_redundancy = "RAID" # RAID or SHR + self.disks_redundancy = "RAID" # RAID or SHR[number][_EXPANSION] def _execute_request(self, method, url, **kwargs): url += urlencode(kwargs["params"]) diff --git a/tests/api_data/dsm_6/__init__.py b/tests/api_data/dsm_6/__init__.py index 3d420c4a..55bdcf92 100644 --- a/tests/api_data/dsm_6/__init__.py +++ b/tests/api_data/dsm_6/__init__.py @@ -10,4 +10,6 @@ from .storage.const_6_storage_storage import ( DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS, DSM_6_STORAGE_STORAGE_DS918_PLUS_RAID5_3DISKS_1VOL, + DSM_6_STORAGE_STORAGE_DS1515_PLUS_SHR2_10DISKS_1VOL_WITH_EXPANSION, + DSM_6_STORAGE_STORAGE_DS1819_PLUS_SHR2_8DISKS_1VOL, ) diff --git a/tests/api_data/dsm_6/storage/const_6_storage_storage.py b/tests/api_data/dsm_6/storage/const_6_storage_storage.py index 94ff8645..6535b9a8 100644 --- a/tests/api_data/dsm_6/storage/const_6_storage_storage.py +++ b/tests/api_data/dsm_6/storage/const_6_storage_storage.py @@ -2,6 +2,1362 @@ """DSM 6 SYNO.Storage.CGI.Storage data.""" from tests.const import UNIQUE_KEY + +DSM_6_STORAGE_STORAGE_DS1819_PLUS_SHR2_8DISKS_1VOL = { + "data": { + "disks": [ + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sda", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 0, + "exceed_bad_sector_thr": False, + "firm": "81.00A81", + "has_system": True, + "id": "sda", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 1", + "model": "WD80EFAX-68KNBN0 ", + "name": "Drive 1", + "num_id": 1, + "order": 1, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "VAHG7V1L", + "size_total": "8001563222016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 39, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdb", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 0, + "exceed_bad_sector_thr": False, + "firm": "81.00A81", + "has_system": True, + "id": "sdb", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 2", + "model": "WD80EFAX-68KNBN0 ", + "name": "Drive 2", + "num_id": 2, + "order": 2, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "VAHGLLPL", + "size_total": "8001563222016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 40, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdc", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 0, + "exceed_bad_sector_thr": False, + "firm": "81.00A81", + "has_system": True, + "id": "sdc", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 3", + "model": "WD80EFAX-68KNBN0 ", + "name": "Drive 3", + "num_id": 3, + "order": 3, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "VAHH38AL", + "size_total": "8001563222016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 40, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdd", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 0, + "exceed_bad_sector_thr": False, + "firm": "81.00A81", + "has_system": True, + "id": "sdd", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 4", + "model": "WD80EFAX-68KNBN0 ", + "name": "Drive 4", + "num_id": 4, + "order": 4, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "VAHGW7VL", + "size_total": "8001563222016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 41, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sde", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 0, + "exceed_bad_sector_thr": False, + "firm": "GX2M", + "has_system": True, + "id": "sde", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 5", + "model": "HDWN180 ", + "name": "Drive 5", + "num_id": 5, + "order": 5, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "399CK0FUFAVG", + "size_total": "8001563222016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 36, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "TOSHIBA ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdf", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 0, + "exceed_bad_sector_thr": False, + "firm": "GX2M", + "has_system": True, + "id": "sdf", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 6", + "model": "HDWN180 ", + "name": "Drive 6", + "num_id": 6, + "order": 6, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "399CK0G0FAVG", + "size_total": "8001563222016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 36, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "TOSHIBA ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdg", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 510, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": True, + "id": "sdg", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 7", + "model": "WD40EFRX-68WT0N0 ", + "name": "Drive 7", + "num_id": 7, + "order": 7, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC4E7PD98ZY", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 33, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1819+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdh", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 488, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": True, + "id": "sdh", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 8", + "model": "WD40EFRX-68N32N0 ", + "name": "Drive 8", + "num_id": 8, + "order": 8, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC7K3FP148E", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 31, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + ], + "env": { + "batchtask": {"max_task": 64, "remain_task": 64}, + "bay_number": "8", + "data_scrubbing": {"sche_enabled": "0", "sche_status": "disabled"}, + "ebox": [], + "fs_acting": False, + "isSyncSysPartition": False, + "is_space_actioning": False, + "isns": {"address": "", "enabled": False}, + "isns_server": "", + "max_fs_bytes": "118747255799808", + "max_fs_bytes_high_end": "219902325555200", + "model_name": "DS1819+", + "ram_enough_for_fs_high_end": False, + "ram_size": 16, + "ram_size_required": 32, + "showpooltab": True, + "status": {"system_crashed": False, "system_need_repair": False}, + "support": {"ebox": True, "raid_cross": True, "sysdef": True}, + "support_fit_fs_limit": True, + "unique_key": UNIQUE_KEY, + "volume_full_critical": 0.1, + "volume_full_warning": 0.2, + }, + "hotSpareConf": {"cross_repair": True, "disable_repair": []}, + "hotSpares": [], + "iscsiLuns": [], + "iscsiTargets": [], + "ports": [], + "ssdCaches": [], + "storagePools": [ + { + "cacheStatus": "", + "can_do": { + "data_scrubbing": True, + "delete": True, + "expand_by_disk": 1, + "raid_cross": True, + }, + "container": "internal", + "desc": "SHR-2", + "device_type": "shr_with_2_disk_protect", + "disk_failure_number": 0, + "disks": ["sda", "sdb", "sdc", "sdd", "sde", "sdf", "sdg", "sdh"], + "drive_type": 0, + "id": "reuse_1", + "is_actioning": False, + "is_scheduled": False, + "is_writable": True, + "last_done_time": 0, + "limited_disk_number": 24, + "maximal_disk_size": "0", + "minimal_disk_size": "8001457274880", + "next_schedule_time": 0, + "num_id": 1, + "pool_child": [{"id": "volume_1", "size": {"total": "39978088267776"}}], + "pool_path": "reuse_1", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "multiple", + "raids": [ + { + "designedDiskCount": 6, + "devices": [ + {"id": "sdf", "slot": 5, "status": "normal"}, + {"id": "sde", "slot": 4, "status": "normal"}, + {"id": "sdd", "slot": 3, "status": "normal"}, + {"id": "sdc", "slot": 2, "status": "normal"}, + {"id": "sdb", "slot": 1, "status": "normal"}, + {"id": "sda", "slot": 0, "status": "normal"}, + ], + "hasParity": True, + "minDevSize": "8001457274880", + "normalDevCount": 6, + "raidPath": "/dev/md3", + "raidStatus": 1, + "spares": [], + }, + { + "designedDiskCount": 8, + "devices": [ + {"id": "sdh", "slot": 7, "status": "normal"}, + {"id": "sdg", "slot": 6, "status": "normal"}, + {"id": "sdf", "slot": 5, "status": "normal"}, + {"id": "sde", "slot": 4, "status": "normal"}, + {"id": "sdd", "slot": 3, "status": "normal"}, + {"id": "sdc", "slot": 2, "status": "normal"}, + {"id": "sdb", "slot": 1, "status": "normal"}, + {"id": "sda", "slot": 0, "status": "normal"}, + ], + "hasParity": True, + "minDevSize": "8001457274880", + "normalDevCount": 8, + "raidPath": "/dev/md2", + "raidStatus": 1, + "spares": [], + }, + ], + "scrubbingStatus": "has_not_run_yet", + "size": {"total": "39978100850688", "used": "39978100850688"}, + "space_path": "/dev/vg1", + "spares": [], + "status": "normal", + "suggestions": [], + "timebackup": False, + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": { + "can_do": False, + "errCode": 768, + "stopService": False, + }, + "remove": { + "can_do": False, + "errCode": 768, + "stopService": False, + }, + "resize": { + "can_do": False, + "errCode": 768, + "stopService": False, + }, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + } + ], + "volumes": [ + { + "atime_checked": False, + "atime_opt": "relatime", + "cacheStatus": "", + "can_do": {"delete": True, "raid_cross": True}, + "container": "internal", + "desc": "Located on Storage Pool 1, SHR", + "device_type": "shr_with_2_disk_protect", + "disk_failure_number": 0, + "disks": [], + "drive_type": 0, + "eppool_used": "0", + "exist_alive_vdsm": False, + "fs_type": "btrfs", + "id": "volume_1", + "is_acting": False, + "is_actioning": False, + "is_inode_full": False, + "is_scheduled": False, + "is_writable": True, + "last_done_time": 0, + "limited_disk_number": 24, + "max_fs_size": "1152921504606846976", + "next_schedule_time": 0, + "num_id": 1, + "pool_path": "reuse_1", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "multiple", + "scrubbingStatus": "", + "size": { + "free_inode": "0", + "total": "38378964738048", + "total_device": "39978088267776", + "total_inode": "0", + "used": "26724878606336", + }, + "ssd_trim": {"support": "not support"}, + "status": "normal", + "suggestions": [], + "timebackup": False, + "used_by_gluster": False, + "vol_path": "/volume1", + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": {"can_do": True, "errCode": 0, "stopService": True}, + "remove": {"can_do": True, "errCode": 0, "stopService": False}, + "resize": {"can_do": True, "errCode": 0, "stopService": False}, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + } + ], + }, + "success": True, +} + +DSM_6_STORAGE_STORAGE_DS1515_PLUS_SHR2_10DISKS_1VOL_WITH_EXPANSION = { + "data": { + "disks": [ + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1515+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sda", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 510, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": True, + "id": "sda", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 1", + "model": "WD40EFRX-68WT0N0 ", + "name": "Drive 1", + "num_id": 1, + "order": 1, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC4E2JL3SNU", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 33, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1515+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdb", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 490, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": True, + "id": "sdb", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 2", + "model": "WD40EFRX-68N32N0 ", + "name": "Drive 2", + "num_id": 2, + "order": 2, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC7K0NAV92K", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 30, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1515+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdc", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 510, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": True, + "id": "sdc", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 3", + "model": "WD40EFRX-68WT0N0 ", + "name": "Drive 3", + "num_id": 3, + "order": 3, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC4E4NTR3PK", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 31, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1515+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sdd", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 510, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": True, + "id": "sdd", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 4", + "model": "WD40EFRX-68WT0N0 ", + "name": "Drive 4", + "num_id": 4, + "order": 4, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC4E2CDEDH1", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 32, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 0, + "str": "DS1515+", + "supportPwrBtnDisable": False, + "type": "internal", + }, + "device": "/dev/sde", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 510, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": True, + "id": "sde", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 5", + "model": "WD40EFRX-68WT0N0 ", + "name": "Drive 5", + "num_id": 5, + "order": 5, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC4E2HAC6NK", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 30, + "testing_progress": "", + "testing_type": "", + "tray_status": "join", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 1, + "str": "DX513-1", + "supportPwrBtnDisable": True, + "type": "ebox", + }, + "device": "/dev/sdga", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 492, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": False, + "id": "sdga", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 1 (DX513-1)", + "model": "WD40EFRX-68N32N0 ", + "name": "Drive 1 (DX513-1)", + "num_id": 1, + "order": 1, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC7K1UZSF9D", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 33, + "testing_progress": "", + "testing_type": "", + "tray_status": "", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 1, + "str": "DX513-1", + "supportPwrBtnDisable": True, + "type": "ebox", + }, + "device": "/dev/sdgb", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 498, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": False, + "id": "sdgb", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 2 (DX513-1)", + "model": "WD40EFRX-68N32N0 ", + "name": "Drive 2 (DX513-1)", + "num_id": 2, + "order": 2, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC7K6ZKJE8Y", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 34, + "testing_progress": "", + "testing_type": "", + "tray_status": "", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 1, + "str": "DX513-1", + "supportPwrBtnDisable": True, + "type": "ebox", + }, + "device": "/dev/sdgc", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 494, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": False, + "id": "sdgc", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 3 (DX513-1)", + "model": "WD40EFRX-68N32N0 ", + "name": "Drive 3 (DX513-1)", + "num_id": 3, + "order": 3, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC7K6AKHYDP", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 35, + "testing_progress": "", + "testing_type": "", + "tray_status": "", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 1, + "str": "DX513-1", + "supportPwrBtnDisable": True, + "type": "ebox", + }, + "device": "/dev/sdgd", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 502, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": False, + "id": "sdgd", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 4 (DX513-1)", + "model": "WD40EFRX-68N32N0 ", + "name": "Drive 4 (DX513-1)", + "num_id": 4, + "order": 4, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC7K7JSL21J", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 35, + "testing_progress": "", + "testing_type": "", + "tray_status": "", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + { + "adv_progress": "", + "adv_status": "not_support", + "below_remain_life_thr": False, + "compatibility": "disabled", + "container": { + "order": 1, + "str": "DX513-1", + "supportPwrBtnDisable": True, + "type": "ebox", + }, + "device": "/dev/sdge", + "disable_secera": False, + "diskType": "SATA", + "disk_code": "", + "erase_time": 508, + "exceed_bad_sector_thr": False, + "firm": "82.00A82", + "has_system": False, + "id": "sdge", + "ihm_testing": False, + "is4Kn": False, + "isSsd": False, + "isSynoPartition": True, + "is_erasing": False, + "longName": "Drive 5 (DX513-1)", + "model": "WD40EFRX-68N32N0 ", + "name": "Drive 5 (DX513-1)", + "num_id": 5, + "order": 5, + "overview_status": "normal", + "pciSlot": -1, + "perf_testing": False, + "portType": "normal", + "remain_life": -1, + "remote_info": {"compatibility": "disabled", "unc": 0}, + "serial": "WD-WCC7K6ZKJJ7S", + "size_total": "4000787030016", + "smart_progress": "", + "smart_status": "normal", + "smart_test_limit": 0, + "smart_testing": False, + "status": "normal", + "support": False, + "temp": 34, + "testing_progress": "", + "testing_type": "", + "tray_status": "", + "unc": 0, + "used_by": "reuse_1", + "vendor": "WDC ", + }, + ], + "env": { + "batchtask": {"max_task": 64, "remain_task": 64}, + "bay_number": "5", + "data_scrubbing": {"sche_enabled": "1", "sche_status": "done"}, + "ebox": [{"id": "sdg", "str": "DX513-1"}], + "fs_acting": False, + "isSyncSysPartition": False, + "is_space_actioning": False, + "isns": {"address": "", "enabled": False}, + "isns_server": "", + "max_fs_bytes": "118747255799808", + "max_fs_bytes_high_end": "219902325555200", + "model_name": "DS1515+", + "ram_enough_for_fs_high_end": False, + "ram_size": 2, + "ram_size_required": 32, + "showpooltab": False, + "status": {"system_crashed": False, "system_need_repair": False}, + "support": {"ebox": True, "raid_cross": True, "sysdef": True}, + "support_fit_fs_limit": True, + "unique_key": UNIQUE_KEY, + "volume_full_critical": 0.1, + "volume_full_warning": 0.2, + }, + "hotSpareConf": {"cross_repair": True, "disable_repair": []}, + "hotSpares": [], + "iscsiLuns": [], + "iscsiTargets": [], + "ports": [], + "ssdCaches": [], + "storagePools": [ + { + "cacheStatus": "", + "can_do": { + "convert_shr_to_pool": 1, + "data_scrubbing": True, + "delete": True, + "expand_by_disk": 1, + "raid_cross": True, + }, + "container": "cross", + "deploy_path": "volume_1", + "desc": "", + "device_type": "shr_with_2_disk_protect", + "disk_failure_number": 0, + "disks": [ + "sda", + "sdb", + "sdc", + "sdd", + "sde", + "sdga", + "sdgb", + "sdgc", + "sdgd", + "sdge", + ], + "drive_type": 0, + "id": "reuse_1", + "is_actioning": False, + "is_scheduled": True, + "is_writable": True, + "last_done_time": 1585897389, + "limited_disk_number": 12, + "maximal_disk_size": "0", + "minimal_disk_size": "4000681082880", + "next_schedule_time": 1588320000, + "num_id": 1, + "pool_path": "reuse_1", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "single", + "raids": [ + { + "designedDiskCount": 10, + "devices": [ + {"id": "sdge", "slot": 6, "status": "normal"}, + {"id": "sdgd", "slot": 7, "status": "normal"}, + {"id": "sdgc", "slot": 8, "status": "normal"}, + {"id": "sdgb", "slot": 9, "status": "normal"}, + {"id": "sdga", "slot": 5, "status": "normal"}, + {"id": "sde", "slot": 4, "status": "normal"}, + {"id": "sdd", "slot": 3, "status": "normal"}, + {"id": "sdc", "slot": 2, "status": "normal"}, + {"id": "sdb", "slot": 1, "status": "normal"}, + {"id": "sda", "slot": 0, "status": "normal"}, + ], + "hasParity": True, + "minDevSize": "4000681082880", + "normalDevCount": 10, + "raidPath": "/dev/md2", + "raidStatus": 1, + "spares": [], + } + ], + "scrubbingStatus": "done", + "size": {"total": "31966715969536", "used": "31966715969536"}, + "space_path": "/dev/vg1000/lv", + "spares": [], + "ssd_trim": {"support": "not support"}, + "status": "normal", + "suggestions": [], + "timebackup": False, + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": {"can_do": True, "errCode": 0, "stopService": True}, + "remove": {"can_do": True, "errCode": 0, "stopService": False}, + "resize": {"can_do": True, "errCode": 0, "stopService": False}, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + } + ], + "volumes": [ + { + "atime_checked": False, + "atime_opt": "relatime", + "cacheStatus": "", + "can_do": { + "convert_shr_to_pool": 1, + "data_scrubbing": True, + "delete": True, + "expand_by_disk": 1, + "raid_cross": True, + }, + "container": "cross", + "deploy_path": "volume_1", + "desc": "", + "device_type": "shr_with_2_disk_protect", + "disk_failure_number": 0, + "disks": [], + "drive_type": 0, + "eppool_used": "0", + "exist_alive_vdsm": False, + "fs_type": "ext4", + "id": "volume_1", + "is_acting": False, + "is_actioning": False, + "is_inode_full": False, + "is_scheduled": True, + "is_writable": True, + "last_done_time": 1585897389, + "limited_disk_number": 12, + "max_fs_size": "1152921504606846976", + "next_schedule_time": 1588320000, + "num_id": 1, + "pool_path": "reuse_1", + "progress": {"percent": "-1", "step": "none"}, + "raidType": "single", + "scrubbingStatus": "done", + "size": { + "free_inode": "974296118", + "total": "31714659872768", + "total_device": "31966715969536", + "total_inode": "975548416", + "used": "25419707531264", + }, + "ssd_trim": {"support": "not support"}, + "status": "normal", + "suggestions": [{"str": "volume_usage_suggestion", "type": "warning"}], + "timebackup": False, + "used_by_gluster": False, + "vol_path": "/volume1", + "vspace_can_do": { + "drbd": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + "flashcache": { + "apply": {"can_do": True, "errCode": 0, "stopService": True}, + "remove": {"can_do": True, "errCode": 0, "stopService": False}, + "resize": {"can_do": True, "errCode": 0, "stopService": False}, + }, + "snapshot": { + "resize": { + "can_do": False, + "errCode": 53504, + "stopService": False, + } + }, + }, + } + ], + }, + "success": True, +} + DSM_6_STORAGE_STORAGE_DS213_PLUS_SHR1_2DISKS_2VOLS = { "data": { "disks": [ diff --git a/tests/test_synology_dsm.py b/tests/test_synology_dsm.py index bc03fa38..0e5abee7 100644 --- a/tests/test_synology_dsm.py +++ b/tests/test_synology_dsm.py @@ -295,7 +295,7 @@ def test_storage_shr_volumes(self): api = SynologyDSMMock( VALID_HOST, VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL ) - api.disks_redundancy = "SHR" + api.disks_redundancy = "SHR1" # Basics assert api.storage.volumes_ids @@ -355,6 +355,68 @@ def test_storage_shr_volumes(self): assert api.storage.volume_disk_temp_avg("test_volume") is None assert api.storage.volume_disk_temp_max("test_volume") is None + def test_storage_shr2_volumes(self): + """Test SHR2 storage volumes.""" + api = SynologyDSMMock( + VALID_HOST, VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL + ) + api.disks_redundancy = "SHR2" + + # Basics + assert api.storage.volumes_ids + for volume_id in api.storage.volumes_ids: + assert api.storage.volume_status(volume_id) + assert api.storage.volume_device_type(volume_id) + assert api.storage.volume_size_total(volume_id) + assert api.storage.volume_size_total(volume_id, False) + assert api.storage.volume_size_used(volume_id) + assert api.storage.volume_size_used(volume_id, False) + assert api.storage.volume_percentage_used(volume_id) + assert api.storage.volume_disk_temp_avg(volume_id) + assert api.storage.volume_disk_temp_max(volume_id) + + # Existing volume + assert api.storage.volume_status("volume_1") == "normal" + assert api.storage.volume_device_type("volume_1") == "shr_with_2_disk_protect" + assert api.storage.volume_size_total("volume_1") == "34.9Tb" + assert api.storage.volume_size_total("volume_1", False) == 38378964738048 + assert api.storage.volume_size_used("volume_1") == "24.3Tb" + assert api.storage.volume_size_used("volume_1", False) == 26724878606336 + assert api.storage.volume_percentage_used("volume_1") == 69.6 + assert api.storage.volume_disk_temp_avg("volume_1") == 37.0 + assert api.storage.volume_disk_temp_max("volume_1") == 41 + + def test_storage_shr2_expansion_volumes(self): + """Test SHR2 storage with expansion unit volumes.""" + api = SynologyDSMMock( + VALID_HOST, VALID_PORT, VALID_USER, VALID_PASSWORD, VALID_SSL + ) + api.disks_redundancy = "SHR2_EXPANSION" + + # Basics + assert api.storage.volumes_ids + for volume_id in api.storage.volumes_ids: + assert api.storage.volume_status(volume_id) + assert api.storage.volume_device_type(volume_id) + assert api.storage.volume_size_total(volume_id) + assert api.storage.volume_size_total(volume_id, False) + assert api.storage.volume_size_used(volume_id) + assert api.storage.volume_size_used(volume_id, False) + assert api.storage.volume_percentage_used(volume_id) + assert api.storage.volume_disk_temp_avg(volume_id) + assert api.storage.volume_disk_temp_max(volume_id) + + # Existing volume + assert api.storage.volume_status("volume_1") == "normal" + assert api.storage.volume_device_type("volume_1") == "shr_with_2_disk_protect" + assert api.storage.volume_size_total("volume_1") == "28.8Tb" + assert api.storage.volume_size_total("volume_1", False) == 31714659872768 + assert api.storage.volume_size_used("volume_1") == "23.1Tb" + assert api.storage.volume_size_used("volume_1", False) == 25419707531264 + assert api.storage.volume_percentage_used("volume_1") == 80.2 + assert api.storage.volume_disk_temp_avg("volume_1") == 33.0 + assert api.storage.volume_disk_temp_max("volume_1") == 35 + def test_storage_disks(self): """Test storage disks.""" # Basics