Skip to content

Commit d93c88c

Browse files
Add LastRebootTime to Device status
Exposes the last reboot timestamp of a device in its status.
1 parent 4d22cc1 commit d93c88c

11 files changed

Lines changed: 70 additions & 1 deletion

File tree

api/core/v1alpha1/device_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ type DeviceStatus struct {
143143
// +optional
144144
FirmwareVersion string `json:"firmwareVersion,omitempty"`
145145

146+
// LastRebootTime is the timestamp of the last reboot of the Device, if known.
147+
// +optional
148+
LastRebootTime metav1.Time `json:"lastRebootTime,omitempty"`
149+
146150
// Provisioning is the list of provisioning attempts for the Device.
147151
// +listType=map
148152
// +listMapKey=startTime
@@ -275,6 +279,7 @@ const (
275279
// +kubebuilder:printcolumn:name="Model",type=string,JSONPath=".status.model",priority=1
276280
// +kubebuilder:printcolumn:name="SerialNumber",type=string,JSONPath=".status.serialNumber",priority=1
277281
// +kubebuilder:printcolumn:name="FirmwareVersion",type=string,JSONPath=".status.firmwareVersion",priority=1
282+
// +kubebuilder:printcolumn:name="RebootTime",type="date",JSONPath=".status.lastRebootTime",priority=1
278283
// +kubebuilder:printcolumn:name="Ports",type=string,JSONPath=".status.portSummary",priority=1
279284
// +kubebuilder:printcolumn:name="Phase",type="string",JSONPath=".status.phase"
280285
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`

api/core/v1alpha1/zz_generated.deepcopy.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/network-operator/templates/crd/devices.networking.metal.ironcore.dev.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ spec:
3939
name: FirmwareVersion
4040
priority: 1
4141
type: string
42+
- jsonPath: .status.lastRebootTime
43+
name: RebootTime
44+
priority: 1
45+
type: date
4246
- jsonPath: .status.portSummary
4347
name: Ports
4448
priority: 1
@@ -368,6 +372,11 @@ spec:
368372
description: FirmwareVersion is the firmware version running on the
369373
Device.
370374
type: string
375+
lastRebootTime:
376+
description: LastRebootTime is the timestamp of the last reboot of
377+
the Device, if known.
378+
format: date-time
379+
type: string
371380
manufacturer:
372381
description: Manufacturer is the manufacturer of the Device.
373382
type: string

config/crd/bases/networking.metal.ironcore.dev_devices.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ spec:
3636
name: FirmwareVersion
3737
priority: 1
3838
type: string
39+
- jsonPath: .status.lastRebootTime
40+
name: RebootTime
41+
priority: 1
42+
type: date
3943
- jsonPath: .status.portSummary
4044
name: Ports
4145
priority: 1
@@ -365,6 +369,11 @@ spec:
365369
description: FirmwareVersion is the firmware version running on the
366370
Device.
367371
type: string
372+
lastRebootTime:
373+
description: LastRebootTime is the timestamp of the last reboot of
374+
the Device, if known.
375+
format: date-time
376+
type: string
368377
manufacturer:
369378
description: Manufacturer is the manufacturer of the Device.
370379
type: string

docs/api-reference/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ _Appears in:_
10021002
| `model` _string_ | Model is the model identifier of the Device. | | Optional: \{\} <br /> |
10031003
| `serialNumber` _string_ | SerialNumber is the serial number of the Device. | | Optional: \{\} <br /> |
10041004
| `firmwareVersion` _string_ | FirmwareVersion is the firmware version running on the Device. | | Optional: \{\} <br /> |
1005+
| `lastRebootTime` _[Time](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#time-v1-meta)_ | LastRebootTime is the timestamp of the last reboot of the Device, if known. | | Optional: \{\} <br /> |
10051006
| `provisioning` _[ProvisioningInfo](#provisioninginfo) array_ | Provisioning is the list of provisioning attempts for the Device. | | Optional: \{\} <br /> |
10061007
| `ports` _[DevicePort](#deviceport) array_ | Ports is the list of ports on the Device. | | Optional: \{\} <br /> |
10071008
| `portSummary` _string_ | PortSummary shows a summary of the port configured, grouped by type, e.g. "1/4 (10g), 3/64 (100g)". | | Optional: \{\} <br /> |

internal/controller/core/device_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ func (r *DeviceReconciler) reconcile(ctx context.Context, device *v1alpha1.Devic
310310
device.Status.Model = info.Model
311311
device.Status.SerialNumber = info.SerialNumber
312312
device.Status.FirmwareVersion = info.FirmwareVersion
313+
device.Status.LastRebootTime = metav1.NewTime(info.LastRebootTime)
313314

314315
conditions.Set(device, metav1.Condition{
315316
Type: v1alpha1.ReadyCondition,

internal/controller/core/device_controller_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ var _ = Describe("Device Controller", func() {
121121
g.Expect(resource.Status.Model).To(Equal("Model"))
122122
g.Expect(resource.Status.SerialNumber).To(Equal("123456789"))
123123
g.Expect(resource.Status.FirmwareVersion).To(Equal("1.0.0"))
124+
g.Expect(resource.Status.LastRebootTime.Time).To(BeTemporally("==", lastRebootTime))
124125

125126
g.Expect(resource.Status.Ports).To(HaveLen(8))
126127
g.Expect(resource.Status.Ports[0].Name).To(Equal("eth1/1"))

internal/controller/core/suite_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ var (
4646
k8sManager ctrl.Manager
4747
testProvider = NewProvider()
4848
testLocker *resourcelock.ResourceLocker
49+
50+
lastRebootTime = time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
4951
)
5052

5153
func TestControllers(t *testing.T) {
@@ -479,6 +481,7 @@ func (p *Provider) GetDeviceInfo(context.Context) (*provider.DeviceInfo, error)
479481
Model: "Model",
480482
SerialNumber: "123456789",
481483
FirmwareVersion: "1.0.0",
484+
LastRebootTime: lastRebootTime,
482485
}, nil
483486
}
484487

internal/provider/cisco/nxos/provider.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ func (p *Provider) GetDeviceInfo(ctx context.Context) (*provider.DeviceInfo, err
182182
m := new(Model)
183183
s := new(SerialNumber)
184184
fw := new(FirmwareVersion)
185-
if err := p.client.GetState(ctx, m, s, fw); err != nil {
185+
bt := new(BootTime)
186+
if err := p.client.GetState(ctx, m, s, fw, bt); err != nil {
186187
return nil, err
187188
}
188189

@@ -191,6 +192,7 @@ func (p *Provider) GetDeviceInfo(ctx context.Context) (*provider.DeviceInfo, err
191192
Model: string(*m),
192193
SerialNumber: string(*s),
193194
FirmwareVersion: string(*fw),
195+
LastRebootTime: bt.Time,
194196
}, nil
195197
}
196198

internal/provider/cisco/nxos/system.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ package nxos
55

66
import (
77
"context"
8+
"encoding/json"
89
"fmt"
10+
"strconv"
11+
"time"
912

1013
"google.golang.org/grpc"
1114

@@ -66,6 +69,38 @@ func (*BootPOAP) XPath() string {
6669
return "/System/boot-items/poap"
6770
}
6871

72+
type BootTime UnixTime
73+
74+
func (*BootTime) XPath() string {
75+
return "System/procsys-items/bootTime"
76+
}
77+
78+
func (t *BootTime) UnmarshalJSON(b []byte) error {
79+
return (*UnixTime)(t).UnmarshalJSON(b)
80+
}
81+
82+
// UnixTime is a wrapper around time.Time that marshals/unmarshals to/from a Unix timestamp in seconds.
83+
type UnixTime struct {
84+
time.Time `json:"-"`
85+
}
86+
87+
// UnmarshalJSON implements json.Unmarshaler.
88+
func (t *UnixTime) UnmarshalJSON(b []byte) error {
89+
var unix int64
90+
if err := json.Unmarshal(b, &unix); err != nil {
91+
var str string
92+
if err := json.Unmarshal(b, &str); err != nil {
93+
return fmt.Errorf("failed to unmarshal UnixTime: %w", err)
94+
}
95+
unix, err = strconv.ParseInt(str, 10, 64)
96+
if err != nil {
97+
return fmt.Errorf("failed to parse UnixTime string: %w", err)
98+
}
99+
}
100+
t.Time = time.Unix(unix, 0)
101+
return nil
102+
}
103+
69104
func Reboot(ctx context.Context, conn *grpc.ClientConn) error {
70105
request := system.RebootRequest{
71106
Method: system.RebootMethod_COLD,

0 commit comments

Comments
 (0)