redfish-python-sdk 1.2.0__tar.gz → 1.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. {redfish_python_sdk-1.2.0/redfish_python_sdk.egg-info → redfish_python_sdk-1.2.3}/PKG-INFO +8 -5
  2. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/README.md +7 -4
  3. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/pyproject.toml +1 -1
  4. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3/redfish_python_sdk.egg-info}/PKG-INFO +8 -5
  5. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_python_sdk.egg-info/SOURCES.txt +22 -0
  6. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/__init__.py +3 -1
  7. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/client.py +132 -2
  8. redfish_python_sdk-1.2.3/redfish_sdk/exceptions.py +200 -0
  9. redfish_python_sdk-1.2.3/redfish_sdk/http_client.py +673 -0
  10. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/_log_helpers.py +40 -7
  11. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/chassis.py +48 -0
  12. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/event.py +3 -0
  13. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/__init__.py +66 -0
  14. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/base.py +476 -0
  15. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/inspur.py +150 -0
  16. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/lenovo.py +247 -0
  17. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/registry.py +72 -0
  18. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/smoothcompute.py +163 -0
  19. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/xfusion.py +41 -0
  20. redfish_python_sdk-1.2.3/redfish_sdk/managers/log_collect_strategies/zte.py +305 -0
  21. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/managers.py +255 -1
  22. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/__init__.py +65 -0
  23. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/base.py +166 -0
  24. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/h3c.py +28 -0
  25. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/inspur.py +50 -0
  26. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/lenovo.py +28 -0
  27. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/nettrix.py +36 -0
  28. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/registry.py +69 -0
  29. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/xfusion.py +30 -0
  30. redfish_python_sdk-1.2.3/redfish_sdk/managers/oem_extractors/zte.py +29 -0
  31. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/vendor_detect.py +3 -0
  32. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/drive.py +4 -0
  33. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/event.py +5 -0
  34. redfish_python_sdk-1.2.3/redfish_sdk/models/log_collect.py +227 -0
  35. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/logs.py +4 -0
  36. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/managers.py +4 -1
  37. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/oem.py +31 -29
  38. redfish_python_sdk-1.2.3/redfish_sdk/models/task.py +101 -0
  39. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/thermal.py +1 -0
  40. redfish_python_sdk-1.2.3/tests/test_exception_hints_mock.py +102 -0
  41. redfish_python_sdk-1.2.3/tests/test_http_retry_mock.py +198 -0
  42. redfish_python_sdk-1.2.3/tests/test_log_collect_mock.py +1791 -0
  43. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_models.py +81 -0
  44. redfish_python_sdk-1.2.3/tests/test_oem_extractors.py +294 -0
  45. redfish_python_sdk-1.2.0/redfish_sdk/exceptions.py +0 -56
  46. redfish_python_sdk-1.2.0/redfish_sdk/http_client.py +0 -452
  47. redfish_python_sdk-1.2.0/redfish_sdk/models/task.py +0 -54
  48. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/LICENSE +0 -0
  49. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_python_sdk.egg-info/dependency_links.txt +0 -0
  50. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_python_sdk.egg-info/requires.txt +0 -0
  51. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_python_sdk.egg-info/top_level.txt +0 -0
  52. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/__init__.py +0 -0
  53. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/account.py +0 -0
  54. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/registries.py +0 -0
  55. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/session.py +0 -0
  56. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/systems.py +0 -0
  57. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/task.py +0 -0
  58. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update.py +0 -0
  59. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/__init__.py +0 -0
  60. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/base.py +0 -0
  61. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/h3c.py +0 -0
  62. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/inspur.py +0 -0
  63. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/lenovo.py +0 -0
  64. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/nettrix.py +0 -0
  65. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/registry.py +0 -0
  66. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/xfusion.py +0 -0
  67. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/managers/update_strategies/zte.py +0 -0
  68. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/__init__.py +0 -0
  69. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/account.py +0 -0
  70. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/chassis.py +0 -0
  71. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/check.py +0 -0
  72. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/common.py +0 -0
  73. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/fru.py +0 -0
  74. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/gpu.py +0 -0
  75. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/memory.py +0 -0
  76. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/network_adapter.py +0 -0
  77. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/pcie_device.py +0 -0
  78. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/power.py +0 -0
  79. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/processor.py +0 -0
  80. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/registry.py +0 -0
  81. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/resource_key.py +0 -0
  82. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/root.py +0 -0
  83. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/session.py +0 -0
  84. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/storage.py +0 -0
  85. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/systems.py +0 -0
  86. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/redfish_sdk/models/update.py +0 -0
  87. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/setup.cfg +0 -0
  88. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_client_mock.py +0 -0
  89. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_log_entries_mock.py +0 -0
  90. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_models_mock.py +0 -0
  91. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_offline_json.py +0 -0
  92. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_real_bmc.py +0 -0
  93. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_sdk_mock.py +0 -0
  94. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_update_strategies.py +0 -0
  95. {redfish_python_sdk-1.2.0 → redfish_python_sdk-1.2.3}/tests/test_v1_1_apis_mock.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redfish-python-sdk
3
- Version: 1.2.0
3
+ Version: 1.2.3
4
4
  Summary: A Python SDK for interacting with Redfish-compliant BMC endpoints
5
5
  Author: RedNote Infrastructure
6
6
  License: BSD 3-Clause License
@@ -63,11 +63,14 @@ Requires-Dist: pytest>=7.0.0; extra == "dev"
63
63
  Requires-Dist: ruff>=0.4.0; extra == "dev"
64
64
  Dynamic: license-file
65
65
 
66
- # Redfish Python SDK
66
+ # redfish-python-sdk
67
+ **redfish-python-sdk** is a typed, high-level Python SDK for managing
68
+ multi-vendor BMCs and bare-metal servers through the DMTF Redfish API.
67
69
 
68
70
  [![PyPI version](https://img.shields.io/pypi/v/redfish-python-sdk)](https://pypi.org/project/redfish-python-sdk/)
69
71
  [![Python versions](https://img.shields.io/pypi/pyversions/redfish-python-sdk)](https://pypi.org/project/redfish-python-sdk/)
70
72
  [![License](https://img.shields.io/pypi/l/redfish-python-sdk)](https://github.com/rednote-infra/redfish-python-sdk/blob/main/LICENSE)
73
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/redfish-python-sdk?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/redfish-python-sdk)
71
74
 
72
75
  [English](README.md) | [中文](README_zh.md)
73
76
 
@@ -97,11 +100,11 @@ pip install redfish-python-sdk
97
100
  pip install git+https://github.com/rednote-infra/redfish-python-sdk.git
98
101
 
99
102
  # Install a specific version
100
- pip install redfish-python-sdk==1.0.0
101
- pip install git+https://github.com/rednote-infra/redfish-python-sdk.git@v1.0.0
103
+ pip install redfish-python-sdk==1.2.3
104
+ pip install git+https://github.com/rednote-infra/redfish-python-sdk.git@v1.2.3
102
105
 
103
106
  # In requirements.txt
104
- # redfish-python-sdk>=1.0.0
107
+ # redfish-python-sdk>=1.2.3
105
108
  ```
106
109
 
107
110
  ## Quick Start
@@ -1,8 +1,11 @@
1
- # Redfish Python SDK
1
+ # redfish-python-sdk
2
+ **redfish-python-sdk** is a typed, high-level Python SDK for managing
3
+ multi-vendor BMCs and bare-metal servers through the DMTF Redfish API.
2
4
 
3
5
  [![PyPI version](https://img.shields.io/pypi/v/redfish-python-sdk)](https://pypi.org/project/redfish-python-sdk/)
4
6
  [![Python versions](https://img.shields.io/pypi/pyversions/redfish-python-sdk)](https://pypi.org/project/redfish-python-sdk/)
5
7
  [![License](https://img.shields.io/pypi/l/redfish-python-sdk)](https://github.com/rednote-infra/redfish-python-sdk/blob/main/LICENSE)
8
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/redfish-python-sdk?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/redfish-python-sdk)
6
9
 
7
10
  [English](README.md) | [中文](README_zh.md)
8
11
 
@@ -32,11 +35,11 @@ pip install redfish-python-sdk
32
35
  pip install git+https://github.com/rednote-infra/redfish-python-sdk.git
33
36
 
34
37
  # Install a specific version
35
- pip install redfish-python-sdk==1.0.0
36
- pip install git+https://github.com/rednote-infra/redfish-python-sdk.git@v1.0.0
38
+ pip install redfish-python-sdk==1.2.3
39
+ pip install git+https://github.com/rednote-infra/redfish-python-sdk.git@v1.2.3
37
40
 
38
41
  # In requirements.txt
39
- # redfish-python-sdk>=1.0.0
42
+ # redfish-python-sdk>=1.2.3
40
43
  ```
41
44
 
42
45
  ## Quick Start
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "redfish-python-sdk"
7
- version = "1.2.0"
7
+ version = "1.2.3"
8
8
  description = "A Python SDK for interacting with Redfish-compliant BMC endpoints"
9
9
  requires-python = ">=3.9"
10
10
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redfish-python-sdk
3
- Version: 1.2.0
3
+ Version: 1.2.3
4
4
  Summary: A Python SDK for interacting with Redfish-compliant BMC endpoints
5
5
  Author: RedNote Infrastructure
6
6
  License: BSD 3-Clause License
@@ -63,11 +63,14 @@ Requires-Dist: pytest>=7.0.0; extra == "dev"
63
63
  Requires-Dist: ruff>=0.4.0; extra == "dev"
64
64
  Dynamic: license-file
65
65
 
66
- # Redfish Python SDK
66
+ # redfish-python-sdk
67
+ **redfish-python-sdk** is a typed, high-level Python SDK for managing
68
+ multi-vendor BMCs and bare-metal servers through the DMTF Redfish API.
67
69
 
68
70
  [![PyPI version](https://img.shields.io/pypi/v/redfish-python-sdk)](https://pypi.org/project/redfish-python-sdk/)
69
71
  [![Python versions](https://img.shields.io/pypi/pyversions/redfish-python-sdk)](https://pypi.org/project/redfish-python-sdk/)
70
72
  [![License](https://img.shields.io/pypi/l/redfish-python-sdk)](https://github.com/rednote-infra/redfish-python-sdk/blob/main/LICENSE)
73
+ [![PyPI Downloads](https://static.pepy.tech/personalized-badge/redfish-python-sdk?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/redfish-python-sdk)
71
74
 
72
75
  [English](README.md) | [中文](README_zh.md)
73
76
 
@@ -97,11 +100,11 @@ pip install redfish-python-sdk
97
100
  pip install git+https://github.com/rednote-infra/redfish-python-sdk.git
98
101
 
99
102
  # Install a specific version
100
- pip install redfish-python-sdk==1.0.0
101
- pip install git+https://github.com/rednote-infra/redfish-python-sdk.git@v1.0.0
103
+ pip install redfish-python-sdk==1.2.3
104
+ pip install git+https://github.com/rednote-infra/redfish-python-sdk.git@v1.2.3
102
105
 
103
106
  # In requirements.txt
104
- # redfish-python-sdk>=1.0.0
107
+ # redfish-python-sdk>=1.2.3
105
108
  ```
106
109
 
107
110
  ## Quick Start
@@ -21,6 +21,23 @@ redfish_sdk/managers/session.py
21
21
  redfish_sdk/managers/systems.py
22
22
  redfish_sdk/managers/task.py
23
23
  redfish_sdk/managers/update.py
24
+ redfish_sdk/managers/log_collect_strategies/__init__.py
25
+ redfish_sdk/managers/log_collect_strategies/base.py
26
+ redfish_sdk/managers/log_collect_strategies/inspur.py
27
+ redfish_sdk/managers/log_collect_strategies/lenovo.py
28
+ redfish_sdk/managers/log_collect_strategies/registry.py
29
+ redfish_sdk/managers/log_collect_strategies/smoothcompute.py
30
+ redfish_sdk/managers/log_collect_strategies/xfusion.py
31
+ redfish_sdk/managers/log_collect_strategies/zte.py
32
+ redfish_sdk/managers/oem_extractors/__init__.py
33
+ redfish_sdk/managers/oem_extractors/base.py
34
+ redfish_sdk/managers/oem_extractors/h3c.py
35
+ redfish_sdk/managers/oem_extractors/inspur.py
36
+ redfish_sdk/managers/oem_extractors/lenovo.py
37
+ redfish_sdk/managers/oem_extractors/nettrix.py
38
+ redfish_sdk/managers/oem_extractors/registry.py
39
+ redfish_sdk/managers/oem_extractors/xfusion.py
40
+ redfish_sdk/managers/oem_extractors/zte.py
24
41
  redfish_sdk/managers/update_strategies/__init__.py
25
42
  redfish_sdk/managers/update_strategies/base.py
26
43
  redfish_sdk/managers/update_strategies/h3c.py
@@ -40,6 +57,7 @@ redfish_sdk/models/drive.py
40
57
  redfish_sdk/models/event.py
41
58
  redfish_sdk/models/fru.py
42
59
  redfish_sdk/models/gpu.py
60
+ redfish_sdk/models/log_collect.py
43
61
  redfish_sdk/models/logs.py
44
62
  redfish_sdk/models/managers.py
45
63
  redfish_sdk/models/memory.py
@@ -58,9 +76,13 @@ redfish_sdk/models/task.py
58
76
  redfish_sdk/models/thermal.py
59
77
  redfish_sdk/models/update.py
60
78
  tests/test_client_mock.py
79
+ tests/test_exception_hints_mock.py
80
+ tests/test_http_retry_mock.py
81
+ tests/test_log_collect_mock.py
61
82
  tests/test_log_entries_mock.py
62
83
  tests/test_models.py
63
84
  tests/test_models_mock.py
85
+ tests/test_oem_extractors.py
64
86
  tests/test_offline_json.py
65
87
  tests/test_real_bmc.py
66
88
  tests/test_sdk_mock.py
@@ -28,6 +28,7 @@ Quick start:
28
28
  """
29
29
  from .client import RedfishClient
30
30
  from .exceptions import (
31
+ LogCollectFailedError,
31
32
  RedfishAuthError,
32
33
  RedfishConnectionError,
33
34
  RedfishException,
@@ -55,7 +56,7 @@ from .models.managers import (
55
56
  from .models.resource_key import RedfishResource
56
57
  from .models.systems import BootOption
57
58
 
58
- __version__ = "1.2.0"
59
+ __version__ = "1.2.3"
59
60
  __author__ = "RedNote Infrastructure"
60
61
 
61
62
  __all__ = [
@@ -67,6 +68,7 @@ __all__ = [
67
68
  "RedfishConnectionError",
68
69
  "RedfishTimeoutError",
69
70
  "RedfishValidationError",
71
+ "LogCollectFailedError",
70
72
  # Models commonly used at API boundary.
71
73
  "BootOption",
72
74
  "DnsService",
@@ -117,6 +117,9 @@ class RedfishClient:
117
117
  connect_timeout: int = 10,
118
118
  read_timeout: int = 30,
119
119
  scheme: str = "https",
120
+ retry_5xx: int = 0,
121
+ retry_on_read_timeout: bool = False,
122
+ retry_backoff: float = 1.0,
120
123
  ):
121
124
  """
122
125
  Initialize the Redfish Client.
@@ -132,6 +135,15 @@ class RedfishClient:
132
135
  connect_timeout: TCP connection timeout in seconds (default 10)
133
136
  read_timeout: HTTP response read timeout in seconds (default 30)
134
137
  scheme: URL scheme — "https" (default) or "http"
138
+ retry_5xx: Extra retries when the BMC returns a 5xx (default 0 —
139
+ no retry). GET/HEAD retry on 500/502/503/504; POST/PATCH/DELETE
140
+ retry only on 503/504 to minimise double-write risk. Useful
141
+ against overloaded / flaky BMCs (e.g. AMI MegaRAC firmware
142
+ that intermittently returns Base.1.x.InternalError).
143
+ retry_on_read_timeout: When True, also retry on read timeouts
144
+ (default False). Same idempotency rule as ``retry_5xx``.
145
+ retry_backoff: Base seconds between retries (linear back-off:
146
+ attempt ``n`` sleeps ``retry_backoff * n``). Default 1.0s.
135
147
  """
136
148
  self._http_client = RedfishHttpClient(
137
149
  host=host,
@@ -142,6 +154,9 @@ class RedfishClient:
142
154
  connect_timeout=connect_timeout,
143
155
  read_timeout=read_timeout,
144
156
  scheme=scheme,
157
+ retry_5xx=retry_5xx,
158
+ retry_on_read_timeout=retry_on_read_timeout,
159
+ retry_backoff=retry_backoff,
145
160
  )
146
161
 
147
162
  # Root service cache
@@ -391,9 +406,20 @@ class RedfishClient:
391
406
  return root.systems.odata_id
392
407
 
393
408
  def _get_task_service(self) -> TaskService:
394
- """Get the TaskService resource."""
409
+ """
410
+ Get the TaskService resource.
411
+
412
+ Prefers the standard ``TaskService`` root link (present on every
413
+ DMTF-conformant BMC we've seen). Falls back to the non-standard
414
+ ``Tasks`` link some SDK-internal models also expose, and finally to
415
+ the well-known path so a very stripped-down BMC still works.
416
+ """
395
417
  root = self._get_root()
396
- return self._http_client.get(root.tasks.odata_id, TaskService)
418
+ link = getattr(root, "task_service", None) or getattr(root, "tasks", None)
419
+ odata_id = getattr(link, "odata_id", None) if link is not None else None
420
+ if not odata_id:
421
+ odata_id = "/redfish/v1/TaskService"
422
+ return self._http_client.get(odata_id, TaskService)
397
423
 
398
424
  def _get_update_service(self) -> UpdateService:
399
425
  """Get the UpdateService resource."""
@@ -914,6 +940,110 @@ class RedfishClient:
914
940
  """
915
941
  return self._managers.log_entries(log_id, manager_id)
916
942
 
943
+ # ------------------------------------------------------------------
944
+ # Out-of-band diagnostic log collection + download
945
+ # ------------------------------------------------------------------
946
+
947
+ def collect_diagnostic_data(
948
+ self,
949
+ diagnostic_data_type: Optional[str] = None,
950
+ log_id: Optional[str] = None,
951
+ manager_id: str = "1",
952
+ oem_params: Optional[dict] = None,
953
+ ) -> Task:
954
+ """
955
+ Trigger ``#LogService.CollectDiagnosticData`` to generate an
956
+ out-of-band diagnostic log bundle.
957
+
958
+ Automatically detects the server vendor and builds the vendor-specific
959
+ request body; the action target is discovered dynamically from the
960
+ LogService ``Actions`` block.
961
+
962
+ Args:
963
+ diagnostic_data_type: ``DiagnosticDataType`` value; ``None`` uses
964
+ the vendor default (OEM when available, else ``Manager``).
965
+ log_id: Log service ID. ``None`` auto-selects the sole service.
966
+ manager_id: Manager ID (default "1").
967
+ oem_params: Optional dict shallow-merged into the request body.
968
+
969
+ Returns:
970
+ A :class:`Task` referencing the asynchronous collection.
971
+ """
972
+ return self._managers.collect_diagnostic_data(
973
+ diagnostic_data_type, log_id, manager_id, oem_params
974
+ )
975
+
976
+ def download_diagnostic_data(
977
+ self,
978
+ task_or_entry,
979
+ output_path: Optional[str] = None,
980
+ ) -> "bytes | str":
981
+ """
982
+ Download the artifact produced by a diagnostic-data collection.
983
+
984
+ Args:
985
+ task_or_entry: A completed :class:`Task` or a :class:`LogEntry`
986
+ carrying ``AdditionalDataURI``.
987
+ output_path: When provided, stream the bundle to this path and
988
+ return the absolute file path; otherwise return ``bytes``.
989
+
990
+ Returns:
991
+ The file bytes, or the absolute written path.
992
+ """
993
+ return self._managers.download_diagnostic_data(task_or_entry, output_path)
994
+
995
+ def collect_and_download_diagnostic_data(
996
+ self,
997
+ output_path: str,
998
+ diagnostic_data_type: Optional[str] = None,
999
+ log_id: Optional[str] = None,
1000
+ manager_id: str = "1",
1001
+ poll_interval: int = 5,
1002
+ timeout: int = 1800,
1003
+ *,
1004
+ reuse_existing: bool = True,
1005
+ max_retries: int = 0,
1006
+ retry_backoff: int = 30,
1007
+ ) -> str:
1008
+ """
1009
+ One-click helper: trigger collection, wait for the task, then download.
1010
+
1011
+ Reuses a prior matching collection when available (``reuse_existing``,
1012
+ default True) and can retry a failed collection up to ``max_retries``
1013
+ times (default 0 — no retry). See
1014
+ :meth:`ManagersManager.collect_and_download_diagnostic_data` for the
1015
+ full behaviour contract.
1016
+
1017
+ Args:
1018
+ output_path: Destination file path for the downloaded bundle.
1019
+ diagnostic_data_type: See :meth:`collect_diagnostic_data`.
1020
+ log_id: See :meth:`collect_diagnostic_data`.
1021
+ manager_id: Manager ID (default "1").
1022
+ poll_interval: Task poll interval in seconds (default 5).
1023
+ timeout: Max wait in seconds (default 1800 — bundles are slow).
1024
+ reuse_existing: Reuse a matching prior task on the BMC when
1025
+ available (default True).
1026
+ max_retries: Extra retries on failure (default 0).
1027
+ retry_backoff: Seconds between retries (default 30).
1028
+
1029
+ Returns:
1030
+ The absolute path of the downloaded file.
1031
+
1032
+ Raises:
1033
+ LogCollectFailedError: When the collection ultimately fails.
1034
+ """
1035
+ return self._managers.collect_and_download_diagnostic_data(
1036
+ output_path,
1037
+ diagnostic_data_type,
1038
+ log_id,
1039
+ manager_id,
1040
+ poll_interval,
1041
+ timeout,
1042
+ reuse_existing=reuse_existing,
1043
+ max_retries=max_retries,
1044
+ retry_backoff=retry_backoff,
1045
+ )
1046
+
917
1047
  def get_network_protocol(self, manager_id: str = "1") -> NetworkProtocol:
918
1048
  """
919
1049
  Get network protocol configuration for a BMC manager.
@@ -0,0 +1,200 @@
1
+ """
2
+ Custom exceptions for the Redfish Python SDK.
3
+ """
4
+
5
+
6
+ class RedfishException(Exception):
7
+ """
8
+ Base exception for all Redfish SDK errors.
9
+
10
+ Raised when a Redfish API call returns a non-successful HTTP status code.
11
+ """
12
+
13
+ def __init__(self, status_code: int, message: str, body: str = ""):
14
+ self.status_code = status_code
15
+ self.message = message
16
+ self.body = body
17
+ super().__init__(f"[HTTP {status_code}] {message}")
18
+
19
+ def __repr__(self) -> str:
20
+ return f"RedfishException(status_code={self.status_code}, message={self.message!r})"
21
+
22
+
23
+ class RedfishNotFoundError(RedfishException):
24
+ """Raised when a resource is not found (HTTP 404)."""
25
+
26
+ def __init__(self, path: str):
27
+ super().__init__(404, f"Resource not found: {path}")
28
+
29
+
30
+ class RedfishAuthError(RedfishException):
31
+ """Raised when authentication fails (HTTP 401 / 403)."""
32
+
33
+ def __init__(self, status_code: int = 401):
34
+ super().__init__(status_code, "Authentication failed. Check username and password.")
35
+
36
+
37
+ class RedfishConnectionError(RedfishException):
38
+ """
39
+ Raised when unable to connect to the BMC.
40
+
41
+ The message includes a category-specific troubleshooting hint derived
42
+ from the underlying ``cause`` so operators can quickly tell apart
43
+ "wrong IP / host down" from "wrong port / Redfish disabled" from
44
+ "TLS / DNS" issues.
45
+
46
+ Attributes:
47
+ host: The BMC host that failed to connect.
48
+ cause: The underlying transport exception (usually from ``requests``
49
+ / ``urllib3``).
50
+ reason: One of ``"refused"``, ``"unreachable"``, ``"dns"``,
51
+ ``"tls"``, ``"other"`` — a coarse category derived from ``cause``.
52
+ """
53
+
54
+ def __init__(self, host: str, cause: Exception = None):
55
+ self.host = host
56
+ self.cause = cause
57
+ self.reason = _classify_connection_cause(cause)
58
+ hint = _connection_hint(host, self.reason)
59
+ super().__init__(
60
+ 0,
61
+ f"Unable to connect to host: {host}. Cause: {cause}. {hint}",
62
+ )
63
+
64
+
65
+ class RedfishTimeoutError(RedfishException):
66
+ """
67
+ Raised when a request times out.
68
+
69
+ Timeout usually means the BMC accepted the TCP connection but is too slow
70
+ to respond (e.g. mid-collection, or under heavy load). It's distinct from
71
+ :class:`RedfishConnectionError`, which means the TCP handshake itself
72
+ never succeeded.
73
+ """
74
+
75
+ def __init__(self, host: str):
76
+ self.host = host
77
+ super().__init__(
78
+ 0,
79
+ f"Request timed out connecting to: {host}. "
80
+ f"Hint: the BMC accepted the TCP connection but did not respond "
81
+ f"within the read timeout — it may be busy (e.g. running a "
82
+ f"diagnostic collection) or overloaded. Consider raising "
83
+ f"``read_timeout`` on RedfishClient, or retrying later.",
84
+ )
85
+
86
+
87
+ class RedfishValidationError(RedfishException):
88
+ """Raised for invalid input parameters (e.g., unsupported reset type)."""
89
+
90
+ def __init__(self, message: str):
91
+ super().__init__(400, message)
92
+
93
+
94
+ class LogCollectFailedError(RedfishException):
95
+ """
96
+ Raised when out-of-band diagnostic-data collection fails on the BMC.
97
+
98
+ Carries the full BMC context so the caller can diagnose without having to
99
+ re-query the BMC: the terminal task state/status, the complete list of
100
+ BMC messages, and (when available) the history of progress snapshots
101
+ observed while polling.
102
+
103
+ Attributes:
104
+ task_id: Task or synthetic-task identifier the collection ran under.
105
+ task_state: Terminal ``TaskState`` reported by the BMC.
106
+ task_status: Terminal ``TaskStatus`` reported by the BMC.
107
+ messages: Full ``Messages`` list from the BMC (each entry retains its
108
+ ``MessageId`` / ``Message`` / ``Severity`` / ``Resolution`` fields).
109
+ progress_history: Optional list of intermediate progress snapshots
110
+ captured during polling — useful for vendors (e.g. ZTE) whose
111
+ progress endpoint replaces earlier state on each poll.
112
+ """
113
+
114
+ def __init__(
115
+ self,
116
+ message: str,
117
+ *,
118
+ task_id: str = "",
119
+ task_state: str = "",
120
+ task_status: str = "",
121
+ messages: list = None,
122
+ progress_history: list = None,
123
+ ):
124
+ super().__init__(500, message)
125
+ self.task_id = task_id
126
+ self.task_state = task_state
127
+ self.task_status = task_status
128
+ self.messages = messages or []
129
+ self.progress_history = progress_history or []
130
+
131
+
132
+ # ---------------------------------------------------------------------------
133
+ # Internal helpers for RedfishConnectionError diagnosis
134
+ # ---------------------------------------------------------------------------
135
+
136
+ # Substrings observed in the string form of common transport failures.
137
+ # Ordered so the most specific matches win when combined into a single blob.
138
+ _CAUSE_MARKERS = (
139
+ ("refused", ("connection refused", "econnrefused", "errno 61", "errno 111")),
140
+ ("unreachable", (
141
+ "no route to host", "network is unreachable", "host is down",
142
+ "ehostunreach", "enetunreach",
143
+ )),
144
+ ("dns", (
145
+ "name or service not known", "nodename nor servname",
146
+ "temporary failure in name resolution", "getaddrinfo failed",
147
+ )),
148
+ ("tls", (
149
+ "ssl", "certificate", "handshake failed", "wrong version number",
150
+ )),
151
+ )
152
+
153
+
154
+ def _classify_connection_cause(cause) -> str:
155
+ """
156
+ Categorise a low-level connection failure so callers can display a
157
+ targeted hint. Returns one of: ``refused`` / ``unreachable`` / ``dns``
158
+ / ``tls`` / ``other``.
159
+ """
160
+ if cause is None:
161
+ return "other"
162
+ blob = f"{cause!r} {cause}".lower()
163
+ for reason, markers in _CAUSE_MARKERS:
164
+ for m in markers:
165
+ if m in blob:
166
+ return reason
167
+ return "other"
168
+
169
+
170
+ def _connection_hint(host: str, reason: str) -> str:
171
+ """Return a one-line, action-oriented hint for the given failure reason."""
172
+ if reason == "refused":
173
+ return (
174
+ f"Hint: {host} accepted routing (host is up) but no service is "
175
+ f"listening on the requested TCP port. Check: 1) the IP is a BMC "
176
+ f"address (not a host OS address); 2) the BMC Redfish/HTTPS "
177
+ f"service is enabled; 3) the port matches your RedfishClient "
178
+ f"``scheme``/port (Redfish default is 443 for https)."
179
+ )
180
+ if reason == "unreachable":
181
+ return (
182
+ f"Hint: {host} is not routable from this machine. Check network "
183
+ f"connectivity (VPN / firewall / VLAN / subnet)."
184
+ )
185
+ if reason == "dns":
186
+ return (
187
+ f"Hint: could not resolve host name {host!r}. Check DNS or use "
188
+ f"the raw IP address instead."
189
+ )
190
+ if reason == "tls":
191
+ return (
192
+ f"Hint: TLS/SSL handshake failed with {host}. BMC self-signed "
193
+ f"certificates are expected — RedfishClient defaults to "
194
+ f"``verify_ssl=False``. If you enabled verification, provide a "
195
+ f"trust store; otherwise check the server's TLS version."
196
+ )
197
+ return (
198
+ f"Hint: unclassified connection failure to {host}. Verify basic "
199
+ f"connectivity with ``ping`` / ``nc -zv {host} 443``."
200
+ )