Skip to main content
Glama
osd.py7.33 kB
""" OSD Domain Models This module contains all data models related to Ceph OSDs. """ from datetime import datetime from typing import Any from pydantic import BaseModel, Field class PerfStat(BaseModel): """Performance statistics for an OSD.""" commit_latency_ms: float = Field( default=0.0, description="Commit latency in milliseconds" ) apply_latency_ms: float = Field( default=0.0, description="Apply latency in milliseconds" ) class OSDStats(BaseModel): """Statistics for an OSD.""" osd: int = Field(..., description="OSD ID") num_pgs: int = Field(default=0, description="Number of placement groups") num_osds: int = Field(default=1, description="Number of OSDs") # Storage capacity in KB kb: int = Field(default=0, description="Total capacity in KB") kb_used: int = Field(default=0, description="Used capacity in KB") kb_avail: int = Field(default=0, description="Available capacity in KB") perf_stat: PerfStat = Field( default_factory=PerfStat, description="Performance statistics" ) alerts: list[Any] = Field(default_factory=list, description="OSD alerts") class Tree(BaseModel): """Tree information for an OSD.""" id: int = Field(..., description="Tree ID") device_class: str = Field(default="", description="Device class (ssd, hdd, nvme)") type: str = Field(default="osd", description="Node type") class Host(BaseModel): """Host information for an OSD.""" name: str = Field(..., description="Host name") class OSD(BaseModel): """Represents a Ceph OSD with all its attributes.""" osd: int = Field(..., description="OSD ID") id: int = Field(..., description="OSD ID (duplicate)") up: int = Field(..., description="Up status (1=up, 0=down)") in_: int = Field(..., alias="in", description="In status (1=in, 0=out)") weight: float = Field(default=1.0, description="OSD weight") operational_status: str = Field(default="", description="Operational status") # Nested objects osd_stats: OSDStats = Field(..., description="OSD statistics") tree: Tree = Field(..., description="Tree information") host: Host = Field(..., description="Host information") def is_up(self) -> bool: """Check if the OSD is up.""" return self.up == 1 def is_down(self) -> bool: """Check if the OSD is down.""" return self.up == 0 def is_in(self) -> bool: """Check if the OSD is in.""" return self.in_ == 1 def is_out(self) -> bool: """Check if the OSD is out.""" return self.in_ == 0 def is_working(self) -> bool: """Check if the OSD is working.""" return str(self.operational_status).lower() == "working" def get_status_display(self) -> str: """Get display-friendly status.""" status_parts = [] status_parts.append("up" if self.is_up() else "down") status_parts.append("in" if self.is_in() else "out") return f"{'/'.join(status_parts)} ({self.operational_status})" def get_capacity_gb(self) -> float: """Get total capacity in GB.""" return round(int(self.osd_stats.kb) / 1024 / 1024, 2) def get_used_gb(self) -> float: """Get used capacity in GB.""" return round(int(self.osd_stats.kb_used) / 1024 / 1024, 2) def get_available_gb(self) -> float: """Get available capacity in GB.""" return round(int(self.osd_stats.kb_avail) / 1024 / 1024, 2) def get_usage_percentage(self) -> float: """Get usage percentage.""" if self.osd_stats.kb == 0: return 0.0 return round((self.osd_stats.kb_used / self.osd_stats.kb) * 100, 2) def get_device_class(self) -> str: """Get device class.""" return str(self.tree.device_class) or "unknown" def get_hostname(self) -> str: """Get hostname.""" return str(self.host.name) class DeviceClassSummary(BaseModel): """Summary information for a specific device class.""" device_class: str = Field(..., description="Device class name") osd_count: int = Field(..., description="Number of OSDs") total_pgs: int = Field(..., description="Total number of placement groups") total_capacity_kb: int = Field(..., description="Total capacity in KB") total_used_kb: int = Field(..., description="Total used capacity in KB") total_available_kb: int = Field(..., description="Total available capacity in KB") def get_total_capacity_gb(self) -> float: """Get total capacity in GB.""" return round(self.total_capacity_kb / 1024 / 1024, 2) def get_total_used_gb(self) -> float: """Get total used capacity in GB.""" return round(self.total_used_kb / 1024 / 1024, 2) def get_total_available_gb(self) -> float: """Get total available capacity in GB.""" return round(self.total_available_kb / 1024 / 1024, 2) class OSDSummary(BaseModel): """Summary information about all OSDs in the cluster.""" total_osds: int = Field(..., description="Total number of OSDs") up_osds: int = Field(..., description="Number of up OSDs") down_osds: int = Field(..., description="Number of down OSDs") in_osds: int = Field(..., description="Number of in OSDs") out_osds: int = Field(..., description="Number of out OSDs") working_osds: int = Field(..., description="Number of working OSDs") unique_hosts: list[str] = Field(..., description="List of unique host names") device_classes: list[str] = Field(..., description="List of unique device classes") device_class_summary: dict[str, DeviceClassSummary] = Field( ..., description="Summary by device class" ) osds: list[OSD] = Field(..., description="List of all OSDs") collected_at: datetime = Field( default_factory=datetime.now, description="Data collection timestamp" ) def get_osd_by_id(self, osd_id: int) -> OSD | None: """Find an OSD by its ID.""" for osd in self.osds: if osd.osd == osd_id: return osd return None def get_osds_by_host(self, hostname: str) -> list[OSD]: """Get all OSDs on a specific host.""" return [osd for osd in self.osds if osd.get_hostname() == hostname] def get_osds_by_device_class(self, device_class: str) -> list[OSD]: """Get all OSDs of a specific device class.""" return [osd for osd in self.osds if osd.get_device_class() == device_class] def get_up_osds(self) -> list[OSD]: """Get list of up OSDs.""" return [osd for osd in self.osds if osd.is_up()] def get_down_osds(self) -> list[OSD]: """Get list of down OSDs.""" return [osd for osd in self.osds if osd.is_down()] def get_working_osds(self) -> list[OSD]: """Get list of working OSDs.""" return [osd for osd in self.osds if osd.is_working()] class OSDIdInfo(BaseModel): """Information about OSD IDs and their hosts.""" osd_ids: list[dict[str, Any]] = Field( ..., description="List of OSD ID and host mappings" ) total_count: int = Field(..., description="Total number of OSDs") collected_at: datetime = Field( default_factory=datetime.now, description="Data collection timestamp" )

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rajmohanram/ceph-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server