redfish-python-sdk 1.0.0__py3-none-any.whl

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 (56) hide show
  1. redfish_python_sdk-1.0.0.dist-info/METADATA +164 -0
  2. redfish_python_sdk-1.0.0.dist-info/RECORD +56 -0
  3. redfish_python_sdk-1.0.0.dist-info/WHEEL +5 -0
  4. redfish_python_sdk-1.0.0.dist-info/licenses/LICENSE +29 -0
  5. redfish_python_sdk-1.0.0.dist-info/top_level.txt +1 -0
  6. redfish_sdk/__init__.py +63 -0
  7. redfish_sdk/client.py +1894 -0
  8. redfish_sdk/exceptions.py +56 -0
  9. redfish_sdk/http_client.py +452 -0
  10. redfish_sdk/managers/__init__.py +21 -0
  11. redfish_sdk/managers/_log_helpers.py +144 -0
  12. redfish_sdk/managers/account.py +96 -0
  13. redfish_sdk/managers/chassis.py +327 -0
  14. redfish_sdk/managers/event.py +264 -0
  15. redfish_sdk/managers/managers.py +120 -0
  16. redfish_sdk/managers/registries.py +48 -0
  17. redfish_sdk/managers/session.py +130 -0
  18. redfish_sdk/managers/systems.py +630 -0
  19. redfish_sdk/managers/task.py +89 -0
  20. redfish_sdk/managers/update.py +99 -0
  21. redfish_sdk/managers/update_strategies/__init__.py +51 -0
  22. redfish_sdk/managers/update_strategies/base.py +101 -0
  23. redfish_sdk/managers/update_strategies/h3c.py +140 -0
  24. redfish_sdk/managers/update_strategies/inspur.py +89 -0
  25. redfish_sdk/managers/update_strategies/lenovo.py +59 -0
  26. redfish_sdk/managers/update_strategies/nettrix.py +56 -0
  27. redfish_sdk/managers/update_strategies/registry.py +72 -0
  28. redfish_sdk/managers/update_strategies/vendor_detect.py +111 -0
  29. redfish_sdk/managers/update_strategies/xfusion.py +60 -0
  30. redfish_sdk/managers/update_strategies/zte.py +68 -0
  31. redfish_sdk/models/__init__.py +55 -0
  32. redfish_sdk/models/account.py +60 -0
  33. redfish_sdk/models/chassis.py +86 -0
  34. redfish_sdk/models/check.py +231 -0
  35. redfish_sdk/models/common.py +102 -0
  36. redfish_sdk/models/drive.py +53 -0
  37. redfish_sdk/models/event.py +64 -0
  38. redfish_sdk/models/fru.py +59 -0
  39. redfish_sdk/models/gpu.py +33 -0
  40. redfish_sdk/models/logs.py +56 -0
  41. redfish_sdk/models/managers.py +153 -0
  42. redfish_sdk/models/memory.py +50 -0
  43. redfish_sdk/models/network_adapter.py +76 -0
  44. redfish_sdk/models/oem.py +173 -0
  45. redfish_sdk/models/pcie_device.py +89 -0
  46. redfish_sdk/models/power.py +92 -0
  47. redfish_sdk/models/processor.py +50 -0
  48. redfish_sdk/models/registry.py +34 -0
  49. redfish_sdk/models/resource_key.py +70 -0
  50. redfish_sdk/models/root.py +50 -0
  51. redfish_sdk/models/session.py +42 -0
  52. redfish_sdk/models/storage.py +77 -0
  53. redfish_sdk/models/systems.py +194 -0
  54. redfish_sdk/models/task.py +54 -0
  55. redfish_sdk/models/thermal.py +111 -0
  56. redfish_sdk/models/update.py +55 -0
@@ -0,0 +1,72 @@
1
+ """
2
+ Update strategy registry — maps vendor keys to strategy instances.
3
+
4
+ Strategies are registered at import time via register(). The registry
5
+ provides a get() method that returns the appropriate strategy for a
6
+ given vendor, falling back to GenericUpdateStrategy for unknown vendors.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import logging
11
+ from typing import Dict
12
+
13
+ from .base import BaseUpdateStrategy, GenericUpdateStrategy
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Singleton fallback strategy
18
+ _GENERIC_STRATEGY = GenericUpdateStrategy()
19
+
20
+
21
+ class UpdateStrategyRegistry:
22
+ """
23
+ Registry mapping vendor keys to update strategy instances.
24
+
25
+ Usage:
26
+ # Registration (done at module import time)
27
+ UpdateStrategyRegistry.register("inspur", InspurUpdateStrategy())
28
+
29
+ # Lookup
30
+ strategy = UpdateStrategyRegistry.get("inspur")
31
+ response = strategy.execute(client, image_uri, ...)
32
+ """
33
+
34
+ _strategies: Dict[str, BaseUpdateStrategy] = {}
35
+
36
+ @classmethod
37
+ def register(cls, vendor: str, strategy: BaseUpdateStrategy) -> None:
38
+ """
39
+ Register a strategy for a vendor.
40
+
41
+ Args:
42
+ vendor: Canonical vendor key (lowercase, e.g., "inspur")
43
+ strategy: Strategy instance
44
+ """
45
+ cls._strategies[vendor.lower()] = strategy
46
+ logger.debug("Registered update strategy for vendor: %s", vendor)
47
+
48
+ @classmethod
49
+ def get(cls, vendor: str) -> BaseUpdateStrategy:
50
+ """
51
+ Get the update strategy for a vendor.
52
+
53
+ Args:
54
+ vendor: Vendor key (case-insensitive)
55
+
56
+ Returns:
57
+ Registered strategy, or GenericUpdateStrategy as fallback
58
+ """
59
+ strategy = cls._strategies.get(vendor.lower())
60
+ if strategy is None:
61
+ logger.warning(
62
+ "No update strategy registered for vendor '%s', "
63
+ "using generic Redfish strategy",
64
+ vendor,
65
+ )
66
+ return _GENERIC_STRATEGY
67
+ return strategy
68
+
69
+ @classmethod
70
+ def registered_vendors(cls) -> list:
71
+ """Return the list of registered vendor keys."""
72
+ return list(cls._strategies.keys())
@@ -0,0 +1,111 @@
1
+ """
2
+ Vendor detection for automatic update strategy routing.
3
+
4
+ Detects the server vendor at runtime by inspecting the System resource's
5
+ Manufacturer field, falling back to OEM key detection.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from typing import TYPE_CHECKING, Dict, List
11
+
12
+ if TYPE_CHECKING:
13
+ from ...client import RedfishClient
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Canonical vendor key -> list of known manufacturer substrings (lowercase)
18
+ _VENDOR_KEYWORDS: Dict[str, List[str]] = {
19
+ "inspur": ["inspur", "浪潮", "maginfra"],
20
+ "zte": ["zte", "中兴"],
21
+ "h3c": ["h3c", "新华三", "h3c servers"],
22
+ "nettrix": ["nettrix", "宁畅"],
23
+ "xfusion": ["xfusion", "超聚变", "huawei"],
24
+ "lenovo": ["lenovo", "联想"],
25
+ }
26
+
27
+
28
+ class VendorDetector:
29
+ """
30
+ Detects the server vendor from the Redfish System resource.
31
+
32
+ Detection order:
33
+ 1. System.Manufacturer field (primary)
34
+ 2. OEM key names in the System resource (fallback)
35
+
36
+ Results are cached per client instance to avoid repeated HTTP calls.
37
+ """
38
+
39
+ # Cache: client id -> detected vendor string
40
+ _cache: Dict[int, str] = {}
41
+
42
+ @classmethod
43
+ def detect(cls, client: RedfishClient) -> str:
44
+ """
45
+ Detect the server vendor for the given client.
46
+
47
+ Args:
48
+ client: RedfishClient instance
49
+
50
+ Returns:
51
+ Canonical vendor key (e.g., "inspur", "zte") or "generic"
52
+ """
53
+ client_id = id(client)
54
+ if client_id in cls._cache:
55
+ return cls._cache[client_id]
56
+
57
+ vendor = cls._detect_from_system(client)
58
+ cls._cache[client_id] = vendor
59
+
60
+ if vendor == "generic":
61
+ logger.warning(
62
+ "Could not detect server vendor, falling back to generic strategy"
63
+ )
64
+ else:
65
+ logger.info("Detected server vendor: %s", vendor)
66
+
67
+ return vendor
68
+
69
+ @classmethod
70
+ def _detect_from_system(cls, client: RedfishClient) -> str:
71
+ """Attempt detection from System.Manufacturer."""
72
+ try:
73
+ system = client.get_system()
74
+ manufacturer = (system.manufacturer or "").lower().strip()
75
+
76
+ if manufacturer:
77
+ for vendor_key, keywords in _VENDOR_KEYWORDS.items():
78
+ for keyword in keywords:
79
+ if keyword.lower() in manufacturer:
80
+ return vendor_key
81
+
82
+ # Fallback: check OEM keys in the raw system response
83
+ return cls._detect_from_oem_keys(client)
84
+ except Exception:
85
+ logger.debug("Vendor detection from System failed, trying OEM keys")
86
+ return cls._detect_from_oem_keys(client)
87
+
88
+ @classmethod
89
+ def _detect_from_oem_keys(cls, client: RedfishClient) -> str:
90
+ """Fallback: detect vendor from OEM key names in System resource."""
91
+ try:
92
+ system = client.get_system()
93
+ if system.oem and system.oem.model_extra:
94
+ extra_keys = {k.lower() for k in system.oem.model_extra.keys()}
95
+ if "lenovo" in extra_keys:
96
+ return "lenovo"
97
+ if "xfusion" in extra_keys:
98
+ return "xfusion"
99
+ if "hpe" in extra_keys or "hp" in extra_keys:
100
+ return "generic" # HPE not adapted yet
101
+ if "dell" in extra_keys:
102
+ return "generic" # Dell not adapted yet
103
+ except Exception:
104
+ logger.debug("Vendor detection from OEM keys failed")
105
+
106
+ return "generic"
107
+
108
+ @classmethod
109
+ def clear_cache(cls) -> None:
110
+ """Clear the vendor detection cache."""
111
+ cls._cache.clear()
@@ -0,0 +1,60 @@
1
+ """
2
+ xFusion (超聚变) firmware update strategy.
3
+
4
+ xFusion BMCs place extension fields at the body top level (not under Oem),
5
+ including PreserveConfig, ActiveMode, and ModuleArray for PSU updates.
6
+
7
+ Reference: UpdateService固件刷新接口 — 超聚变
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ from typing import TYPE_CHECKING, Any, Dict, Optional
13
+
14
+ from ...models.common import RedfishResponse
15
+ from .base import BaseUpdateStrategy
16
+
17
+ if TYPE_CHECKING:
18
+ from ...client import RedfishClient
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class XFusionUpdateStrategy(BaseUpdateStrategy):
24
+ """
25
+ Firmware update strategy for xFusion (超聚变) servers.
26
+
27
+ Supported kwargs:
28
+ preserve_config (bool): Preserve config -> body.PreserveConfig
29
+ active_mode (str): Immediately/ResetBMC -> body.ActiveMode
30
+ module_array (list): PSU module names -> body.ModuleArray
31
+ """
32
+
33
+ def execute(
34
+ self,
35
+ client: RedfishClient,
36
+ image_uri: str,
37
+ transfer_protocol: str = "HTTPS",
38
+ targets: Optional[list] = None,
39
+ **kwargs: Any,
40
+ ) -> RedfishResponse:
41
+ target = self._discover_action_target(client)
42
+
43
+ body: Dict[str, Any] = {
44
+ "ImageURI": image_uri,
45
+ "TransferProtocol": transfer_protocol,
46
+ }
47
+
48
+ # xFusion puts extension fields at body top level
49
+ if "preserve_config" in kwargs:
50
+ body["PreserveConfig"] = bool(kwargs["preserve_config"])
51
+ if kwargs.get("active_mode"):
52
+ body["ActiveMode"] = kwargs["active_mode"]
53
+ if kwargs.get("module_array"):
54
+ body["ModuleArray"] = kwargs["module_array"]
55
+
56
+ logger.info(
57
+ "XFusionUpdateStrategy: triggering SimpleUpdate with ImageURI=%s",
58
+ image_uri,
59
+ )
60
+ return client._http_client.post(target, RedfishResponse, raw_body=body)
@@ -0,0 +1,68 @@
1
+ """
2
+ ZTE (中兴) firmware update strategy.
3
+
4
+ ZTE BMCs extend SimpleUpdate with OEM fields under Oem.Public for
5
+ BMC/BIOS flash selection, config preservation, and apply time.
6
+
7
+ Reference: UpdateService固件刷新接口 — 中兴
8
+ """
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ from typing import TYPE_CHECKING, Any, Dict, Optional
13
+
14
+ from ...models.common import RedfishResponse
15
+ from .base import BaseUpdateStrategy
16
+
17
+ if TYPE_CHECKING:
18
+ from ...client import RedfishClient
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class ZteUpdateStrategy(BaseUpdateStrategy):
24
+ """
25
+ Firmware update strategy for ZTE (中兴) servers.
26
+
27
+ Supported kwargs:
28
+ preserve_config (bool): Preserve config -> Oem.Public.PreserveConf
29
+ bmc_flash (str): Flash1/Flash2/Both -> Oem.Public.BMCFlash
30
+ bios_flash (str): Flash1/Flash2/Both -> Oem.Public.BiosFlash
31
+ apply_time (str): Immediate/OnReset -> Oem.Public.ApplyTime
32
+ """
33
+
34
+ def execute(
35
+ self,
36
+ client: RedfishClient,
37
+ image_uri: str,
38
+ transfer_protocol: str = "HTTPS",
39
+ targets: Optional[list] = None,
40
+ **kwargs: Any,
41
+ ) -> RedfishResponse:
42
+ target = self._discover_action_target(client)
43
+
44
+ body: Dict[str, Any] = {
45
+ "ImageURI": image_uri,
46
+ "TransferProtocol": transfer_protocol,
47
+ }
48
+
49
+ # Build OEM extension
50
+ oem_public: Dict[str, Any] = {}
51
+
52
+ if "preserve_config" in kwargs:
53
+ oem_public["PreserveConf"] = bool(kwargs["preserve_config"])
54
+ if kwargs.get("bmc_flash"):
55
+ oem_public["BMCFlash"] = kwargs["bmc_flash"]
56
+ if kwargs.get("bios_flash"):
57
+ oem_public["BiosFlash"] = kwargs["bios_flash"]
58
+ if kwargs.get("apply_time"):
59
+ oem_public["ApplyTime"] = kwargs["apply_time"]
60
+
61
+ if oem_public:
62
+ body["Oem"] = {"Public": oem_public}
63
+
64
+ logger.info(
65
+ "ZteUpdateStrategy: triggering SimpleUpdate with ImageURI=%s",
66
+ image_uri,
67
+ )
68
+ return client._http_client.post(target, RedfishResponse, raw_body=body)
@@ -0,0 +1,55 @@
1
+ from .account import Account, AccountService, Role
2
+ from .chassis import Chassis, Drive, Fan, NetworkAdapter, PCIeDevice, Power, PowerSupply, Temperature, Thermal
3
+ from .common import Collection, Entity, Link, RedfishError, RedfishResponse, Status
4
+ from .drive import Location # noqa: F401
5
+ from .event import EventService, Subscription
6
+ from .fru import Fru, FruChassis, FruProduct
7
+ from .logs import Log, LogEntry
8
+ from .managers import EthernetInterface, HostInterface, Manager, NetworkProtocol
9
+ from .memory import MemoryLocation # noqa: F401
10
+ from .network_adapter import Controller, ControllerCapabilities # noqa: F401
11
+ from .oem import Bmc, MainBoard, Oem
12
+ from .pcie_device import ( # noqa: F401
13
+ GpuCore,
14
+ GpuPerformanceParameters,
15
+ PCIeDeviceOEM,
16
+ PCIeDeviceOEMPublic,
17
+ PCIeInterface,
18
+ )
19
+ from .power import InputRange, PowerControl, Voltage # noqa: F401
20
+
21
+ # Additional component models (also available via individual modules)
22
+ from .processor import ProcessorId # noqa: F401
23
+ from .registry import Registry
24
+ from .root import RootService
25
+ from .session import Session, SessionService
26
+ from .storage import CacheSummary, Identifier, StorageController # noqa: F401
27
+ from .systems import Bios, Boot, Gpu, GpuOEM, Memory, Processor, Storage, System, Volume
28
+ from .task import Task, TaskService
29
+ from .thermal import HistoricalInletTempEntry, InletHistoryTemperature, Redundancy # noqa: F401
30
+ from .update import ClientCertificate, FirmwareInventory, UpdateService
31
+
32
+ __all__ = [
33
+ "Link", "Entity", "Collection", "Status", "RedfishResponse", "RedfishError",
34
+ "RootService",
35
+ "System", "Processor", "Memory", "Storage", "Volume", "Bios", "Boot", "Gpu", "GpuOEM",
36
+ "Chassis", "Drive", "NetworkAdapter", "Power", "PowerSupply", "Thermal",
37
+ "PCIeDevice", "Fan", "Temperature",
38
+ "Manager", "NetworkProtocol", "EthernetInterface", "HostInterface",
39
+ "AccountService", "Account", "Role",
40
+ "SessionService", "Session",
41
+ "EventService", "Subscription",
42
+ "UpdateService", "FirmwareInventory", "ClientCertificate",
43
+ "Registry",
44
+ "TaskService", "Task",
45
+ "Oem", "Bmc", "MainBoard",
46
+ "Log", "LogEntry",
47
+ "Fru", "FruChassis", "FruProduct",
48
+ # Additional component models
49
+ "ProcessorId", "MemoryLocation", "StorageController", "CacheSummary", "Identifier",
50
+ "Location", "Controller", "ControllerCapabilities",
51
+ "PCIeInterface", "PCIeDeviceOEM", "PCIeDeviceOEMPublic",
52
+ "GpuCore", "GpuPerformanceParameters",
53
+ "PowerControl", "Voltage", "InputRange", "Redundancy",
54
+ "InletHistoryTemperature", "HistoricalInletTempEntry",
55
+ ]
@@ -0,0 +1,60 @@
1
+ """
2
+ Account service models.
3
+ """
4
+ from __future__ import annotations
5
+
6
+ from typing import List, Optional
7
+
8
+ from pydantic import Field
9
+
10
+ from .common import Entity, Link, Status
11
+ from .oem import Oem
12
+
13
+
14
+ class AccountService(Entity):
15
+ """
16
+ The Account service provides user account management.
17
+ Endpoint: /redfish/v1/AccountService
18
+ """
19
+ accounts: Optional[Link] = Field(None, alias="Accounts")
20
+ roles: Optional[Link] = Field(None, alias="Roles")
21
+ auth_failure_logging_threshold: Optional[int] = Field(
22
+ None, alias="AuthFailureLoggingThreshold"
23
+ )
24
+ max_password_length: Optional[int] = Field(None, alias="MaxPasswordLength")
25
+ min_password_length: Optional[int] = Field(None, alias="MinPasswordLength")
26
+ account_lockout_threshold: Optional[int] = Field(None, alias="AccountLockoutThreshold")
27
+ account_lockout_duration: Optional[int] = Field(None, alias="AccountLockoutDuration")
28
+ service_enabled: Optional[bool] = Field(None, alias="ServiceEnabled")
29
+ status: Optional[Status] = Field(None, alias="Status")
30
+
31
+
32
+ class Account(Entity):
33
+ """
34
+ Represents a user account on the BMC.
35
+ Endpoint: /redfish/v1/AccountService/Accounts/{accountId}
36
+
37
+ """
38
+ account_types: Optional[List[str]] = Field(None, alias="AccountTypes")
39
+ certificates: Optional[Link] = Field(None, alias="Certificates")
40
+ email_address: Optional[str] = Field(None, alias="EmailAddress")
41
+ enabled: Optional[bool] = Field(None, alias="Enabled")
42
+ locked: Optional[bool] = Field(None, alias="Locked")
43
+ password: Optional[str] = Field(None, alias="Password")
44
+ password_change_required: Optional[bool] = Field(None, alias="PasswordChangeRequired")
45
+ phone_number: Optional[str] = Field(None, alias="PhoneNumber")
46
+ role_id: Optional[str] = Field(None, alias="RoleId")
47
+ user_name: Optional[str] = Field(None, alias="UserName")
48
+ oem: Optional[Oem] = Field(None, alias="Oem")
49
+
50
+
51
+ class Role(Entity):
52
+ """
53
+ Represents an account role with associated privileges.
54
+ Endpoint: /redfish/v1/AccountService/Roles/{roleId}
55
+ """
56
+ assigned_privileges: Optional[List[str]] = Field(None, alias="AssignedPrivileges")
57
+ is_predefined: Optional[bool] = Field(None, alias="IsPredefined")
58
+ oem_privileges: Optional[List[str]] = Field(None, alias="OemPrivileges")
59
+ role_id: Optional[str] = Field(None, alias="RoleId")
60
+ status: Optional[Status] = Field(None, alias="Status")
@@ -0,0 +1,86 @@
1
+ """
2
+ Chassis resource models.
3
+ """
4
+ from __future__ import annotations
5
+
6
+ from typing import List, Optional
7
+
8
+ from pydantic import BaseModel, ConfigDict, Field
9
+
10
+ from .common import Entity, Link, Status
11
+ from .drive import Drive, Location # noqa: F401
12
+ from .network_adapter import ( # noqa: F401
13
+ NPAR,
14
+ Controller,
15
+ ControllerCapabilities,
16
+ DataCenterBridging,
17
+ NetworkAdapter,
18
+ VirtualFunction,
19
+ VirtualizationOffload,
20
+ )
21
+ from .oem import Oem
22
+ from .pcie_device import ( # noqa: F401
23
+ GpuCore,
24
+ GpuPerformanceParameters,
25
+ PCIeDevice,
26
+ PCIeDeviceOEM,
27
+ PCIeDeviceOEMPublic,
28
+ PCIeInterface,
29
+ )
30
+ from .power import ( # noqa: F401
31
+ InputRange,
32
+ Power,
33
+ PowerControl,
34
+ PowerSupply,
35
+ Voltage,
36
+ )
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # Re-export component models for backward compatibility
40
+ # ---------------------------------------------------------------------------
41
+ from .thermal import Fan, Redundancy, Temperature, Thermal # noqa: F401
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # Chassis
45
+ # ---------------------------------------------------------------------------
46
+
47
+ class ChassisLinks(BaseModel):
48
+ """Links section within a Chassis resource."""
49
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
50
+ drives: Optional[List[Link]] = Field(None, alias="Drives")
51
+ pcie_devices: Optional[List[Link]] = Field(None, alias="PCIeDevices")
52
+ managed_by: Optional[List[Link]] = Field(None, alias="ManagedBy")
53
+ contains: Optional[List[Link]] = Field(None, alias="Contains")
54
+ contained_by: Optional[Link] = Field(None, alias="ContainedBy")
55
+ computer_systems: Optional[List[Link]] = Field(None, alias="ComputerSystems")
56
+
57
+
58
+ class Chassis(Entity):
59
+ """
60
+ Represents a physical chassis (server enclosure).
61
+ Endpoint: /redfish/v1/Chassis/{chassisId}
62
+
63
+ """
64
+ uuid: Optional[str] = Field(None, alias="UUID")
65
+ links: Optional[ChassisLinks] = Field(None, alias="Links")
66
+ asset_tag: Optional[str] = Field(None, alias="AssetTag")
67
+ chassis_type: Optional[str] = Field(None, alias="ChassisType")
68
+ depth_mm: Optional[float] = Field(None, alias="DepthMm")
69
+ height_mm: Optional[float] = Field(None, alias="HeightMm")
70
+ indicator_led: Optional[str] = Field(None, alias="IndicatorLED")
71
+ manufacturer: Optional[str] = Field(None, alias="Manufacturer")
72
+ model: Optional[str] = Field(None, alias="Model")
73
+ drives: Optional[Link] = Field(None, alias="Drives")
74
+ part_number: Optional[str] = Field(None, alias="PartNumber")
75
+ power: Optional[Link] = Field(None, alias="Power")
76
+ power_state: Optional[str] = Field(None, alias="PowerState")
77
+ sku: Optional[str] = Field(None, alias="SKU")
78
+ serial_number: Optional[str] = Field(None, alias="SerialNumber")
79
+ status: Optional[Status] = Field(None, alias="Status")
80
+ thermal: Optional[Link] = Field(None, alias="Thermal")
81
+ weight_kg: Optional[float] = Field(None, alias="WeightKg")
82
+ width_mm: Optional[float] = Field(None, alias="WidthMm")
83
+ pcie_devices: Optional[Link] = Field(None, alias="PCIeDevices")
84
+ network_adapters: Optional[Link] = Field(None, alias="NetworkAdapters")
85
+ sensors: Optional[Link] = Field(None, alias="Sensors")
86
+ oem: Optional[Oem] = Field(None, alias="Oem")