Skip to content

Commit 7a37830

Browse files
authored
Add high-value Ironic fields to baremetal node views (#2082)
Add conductor, fault, maintenance_reason, description, owner, lessee, traits, allocation_uuid and provision_updated_at to the API model, data extraction and frontend (list + detail page). AI-assisted: Claude Code Signed-off-by: Christian Berendt <berendt@osism.tech>
1 parent 94c3278 commit 7a37830

5 files changed

Lines changed: 111 additions & 2 deletions

File tree

frontend/app/nodes/[uuid]/page.tsx

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,22 @@ export default function NodeDetailPage({ params }: { params: Promise<{ uuid: str
154154
)}
155155
</dd>
156156
</div>
157+
{node.maintenance && node.maintenance_reason && (
158+
<div className="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
159+
<dt className="text-sm font-medium text-gray-500">Maintenance Reason</dt>
160+
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.maintenance_reason}</dd>
161+
</div>
162+
)}
163+
{node.fault && (
164+
<div className="bg-red-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
165+
<dt className="text-sm font-medium text-red-500">Fault</dt>
166+
<dd className="mt-1 sm:mt-0 sm:col-span-2">
167+
<span className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">
168+
{node.fault}
169+
</span>
170+
</dd>
171+
</div>
172+
)}
157173
{node.driver && (
158174
<div className="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
159175
<dt className="text-sm font-medium text-gray-500">Driver</dt>
@@ -181,12 +197,60 @@ export default function NodeDetailPage({ params }: { params: Promise<{ uuid: str
181197
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.resource_class}</dd>
182198
</div>
183199
)}
184-
{node.instance_uuid && (
200+
{node.conductor && (
201+
<div className="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
202+
<dt className="text-sm font-medium text-gray-500">Conductor</dt>
203+
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.conductor}</dd>
204+
</div>
205+
)}
206+
{node.description && (
207+
<div className="bg-white px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
208+
<dt className="text-sm font-medium text-gray-500">Description</dt>
209+
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.description}</dd>
210+
</div>
211+
)}
212+
{node.owner && (
213+
<div className="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
214+
<dt className="text-sm font-medium text-gray-500">Owner</dt>
215+
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.owner}</dd>
216+
</div>
217+
)}
218+
{node.lessee && (
219+
<div className="bg-white px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
220+
<dt className="text-sm font-medium text-gray-500">Lessee</dt>
221+
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.lessee}</dd>
222+
</div>
223+
)}
224+
{node.traits && node.traits.length > 0 && (
185225
<div className="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
226+
<dt className="text-sm font-medium text-gray-500">Traits</dt>
227+
<dd className="mt-1 sm:mt-0 sm:col-span-2 flex flex-wrap gap-1">
228+
{node.traits.map((trait) => (
229+
<span key={trait} className="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-indigo-100 text-indigo-800">
230+
{trait}
231+
</span>
232+
))}
233+
</dd>
234+
</div>
235+
)}
236+
{node.instance_uuid && (
237+
<div className="bg-white px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
186238
<dt className="text-sm font-medium text-gray-500">Instance UUID</dt>
187239
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.instance_uuid}</dd>
188240
</div>
189241
)}
242+
{node.allocation_uuid && (
243+
<div className="bg-gray-50 px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
244+
<dt className="text-sm font-medium text-gray-500">Allocation UUID</dt>
245+
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{node.allocation_uuid}</dd>
246+
</div>
247+
)}
248+
{node.provision_updated_at && (
249+
<div className="bg-white px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
250+
<dt className="text-sm font-medium text-gray-500">Provision Updated</dt>
251+
<dd className="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">{new Date(node.provision_updated_at).toLocaleString()}</dd>
252+
</div>
253+
)}
190254
{node.created_at && (
191255
<div className="bg-white px-4 py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
192256
<dt className="text-sm font-medium text-gray-500">Created</dt>

frontend/app/nodes/page.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,18 @@ export default function NodesPage() {
245245
</span>
246246
)}
247247
{node.maintenance && (
248-
<span className="ml-2 px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800">
248+
<span
249+
className="ml-2 px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-yellow-100 text-yellow-800"
250+
title={node.maintenance_reason || undefined}
251+
>
249252
Maintenance
250253
</span>
251254
)}
255+
{node.fault && (
256+
<span className="ml-2 px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">
257+
Fault: {node.fault}
258+
</span>
259+
)}
252260
</div>
253261
<div className="flex items-center justify-end gap-2">
254262
<span className={`px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${

frontend/lib/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,22 @@ export interface BaremetalNode {
55
power_state: string | null;
66
provision_state: string | null;
77
maintenance: boolean | null;
8+
maintenance_reason: string | null;
9+
fault: string | null;
810
instance_uuid: string | null;
911
driver: string | null;
1012
resource_class: string | null;
13+
conductor: string | null;
14+
owner: string | null;
15+
lessee: string | null;
16+
description: string | null;
17+
allocation_uuid: string | null;
18+
traits: string[];
1119
properties: Record<string, unknown>;
1220
extra: Record<string, unknown>;
1321
redfish_address: string | null;
1422
last_error: string | null;
23+
provision_updated_at: string | null;
1524
created_at: string | null;
1625
updated_at: string | null;
1726
}

osism/api.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ class BaremetalNode(BaseModel):
139139
maintenance: Optional[bool] = Field(
140140
None, description="Whether node is in maintenance mode"
141141
)
142+
maintenance_reason: Optional[str] = Field(
143+
None, description="Reason for maintenance mode"
144+
)
145+
fault: Optional[str] = Field(
146+
None, description="Fault type indicating error category"
147+
)
142148
instance_uuid: Optional[str] = Field(
143149
None, description="UUID of associated instance"
144150
)
@@ -147,6 +153,16 @@ class BaremetalNode(BaseModel):
147153
resource_class: Optional[str] = Field(
148154
None, description="Resource class of the node"
149155
)
156+
conductor: Optional[str] = Field(None, description="Conductor managing this node")
157+
owner: Optional[str] = Field(None, description="Owner of the node")
158+
lessee: Optional[str] = Field(None, description="Lessee of the node")
159+
description: Optional[str] = Field(None, description="Description of the node")
160+
allocation_uuid: Optional[str] = Field(
161+
None, description="UUID of the allocation for this node"
162+
)
163+
traits: list[str] = Field(
164+
default_factory=list, description="List of traits for the node"
165+
)
150166
properties: Dict[str, Any] = Field(
151167
default_factory=dict, description="Node properties"
152168
)
@@ -157,6 +173,9 @@ class BaremetalNode(BaseModel):
157173
None, description="Redfish address from driver_info"
158174
)
159175
last_error: Optional[str] = Field(None, description="Last error message")
176+
provision_updated_at: Optional[str] = Field(
177+
None, description="Timestamp of last provision state change"
178+
)
160179
created_at: Optional[str] = Field(None, description="Creation timestamp")
161180
updated_at: Optional[str] = Field(None, description="Last update timestamp")
162181

osism/tasks/openstack.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,24 @@ def get_baremetal_nodes():
115115
"power_state": getattr(node, "power_state", None),
116116
"provision_state": getattr(node, "provision_state", None),
117117
"maintenance": getattr(node, "maintenance", None),
118+
"maintenance_reason": getattr(node, "maintenance_reason", None),
119+
"fault": getattr(node, "fault", None),
118120
"instance_uuid": getattr(node, "instance_uuid", None),
119121
"driver": getattr(node, "driver", None),
120122
"resource_class": getattr(node, "resource_class", None),
123+
"conductor": getattr(node, "conductor", None),
124+
"owner": getattr(node, "owner", None),
125+
"lessee": getattr(node, "lessee", None),
126+
"description": getattr(node, "description", None),
127+
"allocation_uuid": getattr(node, "allocation_uuid", None),
128+
"traits": getattr(node, "traits", None) or [],
121129
"properties": getattr(node, "properties", {}),
122130
"extra": getattr(node, "extra", {}),
123131
"redfish_address": (getattr(node, "driver_info", None) or {}).get(
124132
"redfish_address"
125133
),
126134
"last_error": getattr(node, "last_error", None),
135+
"provision_updated_at": getattr(node, "provision_updated_at", None),
127136
"created_at": getattr(node, "created_at", None),
128137
"updated_at": getattr(node, "updated_at", None),
129138
}

0 commit comments

Comments
 (0)