Skip to content

Commit b80b607

Browse files
committed
Add ptpconfig status condition
Signed-off-by: Aneesh Puttur <[email protected]>
1 parent 4fc7e9f commit b80b607

File tree

7 files changed

+421
-0
lines changed

7 files changed

+421
-0
lines changed

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
- [PTP Operator](#ptp-operator)
55
- [PtpOperatorConfig](#ptpoperatorconfig)
66
- [PtpConfig](#ptpconfig)
7+
- [PtpConfig Status](#ptpconfig-status)
78
- [Quick Start](#quick-start)
89

910
## PTP Operator
@@ -314,6 +315,42 @@ Two ptp4l configurations must exist with the phc2sysOPts field set to an empty s
314315
The names of these ptp4l configurations will be used and listed under the ptpSettings/haProfiles key in the phc2sys-only enabled ptpConfig.
315316

316317

318+
## PtpConfig Status
319+
PtpConfig includes a status subresource with `ptpStatus.conditions[]` that operands (linuxptp-daemon, cloud-event-proxy) can update. Each condition includes `type`, `profile` (logical profile), `filename` (active config file), `status`, `reason`, `message`, and `lastUpdateTime`.
320+
321+
Example populated status:
322+
```yaml
323+
status:
324+
matchList:
325+
- nodeName: worker-0
326+
profile: GM-Profile-A
327+
ptpStatus:
328+
conditions:
329+
- type: PTP4lRunning
330+
profile: GM-Profile-A
331+
filename: ptp4l.0.config
332+
status: "True"
333+
reason: Started
334+
message: "ptp4l is running (pid 3124)"
335+
lastUpdateTime: "2025-06-27T10:13:10Z"
336+
- type: LockState
337+
profile: GM-Profile-A
338+
filename: ptp4l.0.config
339+
status: "True"
340+
reason: LOCKED
341+
message: "clock state is LOCKED"
342+
lastUpdateTime: "2025-06-27T10:15:00Z"
343+
- type: ClockClass
344+
profile: GM-Profile-A
345+
filename: /ptp4l.0.config
346+
status: "True"
347+
reason: Class6
348+
message: "clock class is 6"
349+
lastUpdateTime: "2025-06-27T10:15:00Z"
350+
```
351+
352+
RBAC for linuxptp-daemon to update `ptpconfigs/status` is included in `bindata/linuxptp/ptp-daemon.yaml`.
353+
317354
## Quick Start
318355

319356
To install PTP Operator:

api/v1/ptpconfig_types.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1
1818

1919
import (
20+
corev1 "k8s.io/api/core/v1"
2021
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2122
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2223
)
@@ -38,6 +39,7 @@ type PtpConfigStatus struct {
3839
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
3940
// Important: Run "make" to regenerate code after modifying this file
4041
MatchList []NodeMatchList `json:"matchList,omitempty"`
42+
PtpStatus PtpStatus `json:"ptpStatus,omitempty"`
4143
}
4244

4345
//+kubebuilder:object:root=true
@@ -112,6 +114,56 @@ type NodeMatchList struct {
112114
Profile *string `json:"profile"`
113115
}
114116

117+
// PtpConditionType represents categories of PTP conditions reported by operands
118+
type PtpConditionType string
119+
120+
const (
121+
// Process lifecycle
122+
ConditionPodRestarted PtpConditionType = "PodRestarted"
123+
ConditionPTP4lRunning PtpConditionType = "PTP4lRunning"
124+
ConditionPhc2sysRunning PtpConditionType = "Phc2sysRunning"
125+
ConditionTs2phcRunning PtpConditionType = "Ts2phcRunning"
126+
ConditionSynce4lRunning PtpConditionType = "Synce4lRunning"
127+
ConditionChronydRunning PtpConditionType = "ChronydRunning"
128+
129+
// Profile/apply
130+
ConditionProfileApplied PtpConditionType = "ProfileApplied"
131+
132+
// NIC/PHC capabilities
133+
ConditionNICCapabilities PtpConditionType = "NICCapabilities"
134+
135+
// State and class (values reflected in Reason/Message)
136+
ConditionLockState PtpConditionType = "LockState" // LOCKED/HOLDOVER/FREERUN
137+
ConditionClockClass PtpConditionType = "ClockClass" // 6/7/248
138+
ConditionPortState PtpConditionType = "PortState" // INITIALIZING/LISTENING/SLAVE/MASTER/FAULTY
139+
140+
// Event/CEP
141+
ConditionEventFramework PtpConditionType = "EventFramework"
142+
143+
// GNSS/DPLL (when applicable)
144+
ConditionGNSSState PtpConditionType = "GNSSState"
145+
ConditionDPLLStatus PtpConditionType = "DPLLStatus"
146+
147+
// Overall service readiness
148+
ConditionPTPServiceReady PtpConditionType = "PTPServiceReady"
149+
)
150+
151+
// PtpCondition mirrors standard Kubernetes condition patterns
152+
type PtpCondition struct {
153+
Type PtpConditionType `json:"type"`
154+
Profile string `json:"profile,omitempty"`
155+
Filename string `json:"filename,omitempty"`
156+
Status corev1.ConditionStatus `json:"status"`
157+
Reason string `json:"reason,omitempty"`
158+
Message string `json:"message,omitempty"`
159+
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
160+
}
161+
162+
// PtpStatus aggregates conditions emitted by operands for this PtpConfig
163+
type PtpStatus struct {
164+
Conditions []PtpCondition `json:"conditions,omitempty"`
165+
}
166+
115167
func init() {
116168
SchemeBuilder.Register(&PtpConfig{}, &PtpConfigList{})
117169
}

api/v1/zz_generated.deepcopy.go

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

bindata/linuxptp/ptp-daemon.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,35 @@ subjects:
227227
name: prometheus-k8s
228228
namespace: openshift-monitoring
229229
---
230+
apiVersion: rbac.authorization.k8s.io/v1
231+
kind: Role
232+
metadata:
233+
name: ptpconfig-status-writer
234+
namespace: openshift-ptp
235+
rules:
236+
- apiGroups:
237+
- ptp.openshift.io
238+
resources:
239+
- ptpconfigs/status
240+
verbs:
241+
- get
242+
- update
243+
- patch
244+
---
245+
apiVersion: rbac.authorization.k8s.io/v1
246+
kind: RoleBinding
247+
metadata:
248+
name: ptpconfig-status-writer-linuxptp
249+
namespace: openshift-ptp
250+
subjects:
251+
- kind: ServiceAccount
252+
name: linuxptp-daemon
253+
namespace: openshift-ptp
254+
roleRef:
255+
apiGroup: rbac.authorization.k8s.io
256+
kind: Role
257+
name: ptpconfig-status-writer
258+
---
230259
apiVersion: monitoring.coreos.com/v1
231260
kind: PrometheusRule
232261
metadata:

config/crd/bases/ptp.openshift.io_ptpconfigs.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,38 @@ spec:
150150
- profile
151151
type: object
152152
type: array
153+
ptpStatus:
154+
description: PtpStatus aggregates conditions emitted by operands for
155+
this PtpConfig
156+
properties:
157+
conditions:
158+
items:
159+
description: PtpCondition mirrors standard Kubernetes condition
160+
patterns
161+
properties:
162+
filename:
163+
type: string
164+
lastUpdateTime:
165+
format: date-time
166+
type: string
167+
message:
168+
type: string
169+
profile:
170+
type: string
171+
reason:
172+
type: string
173+
status:
174+
type: string
175+
type:
176+
description: PtpConditionType represents categories of PTP
177+
conditions reported by operands
178+
type: string
179+
required:
180+
- status
181+
- type
182+
type: object
183+
type: array
184+
type: object
153185
type: object
154186
type: object
155187
served: true

pkg/status/ptpconfig_status.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package status
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/apimachinery/pkg/util/wait"
9+
10+
ptpv1 "github.com/k8snetworkplumbingwg/ptp-operator/api/v1"
11+
clientset "github.com/k8snetworkplumbingwg/ptp-operator/pkg/client/clientset/versioned"
12+
)
13+
14+
// UpsertPtpCondition updates or appends a condition on the PtpConfig status and issues UpdateStatus with retry
15+
func UpsertPtpCondition(ctx context.Context, cs clientset.Interface, namespace, name string, cond ptpv1.PtpCondition) error {
16+
backoff := wait.Backoff{Duration: 100 * time.Millisecond, Factor: 1.5, Jitter: 0.1, Steps: 6}
17+
return wait.ExponentialBackoff(backoff, func() (bool, error) {
18+
pc, err := cs.PtpV1().PtpConfigs(namespace).Get(ctx, name, metav1.GetOptions{})
19+
if err != nil {
20+
return false, err
21+
}
22+
23+
// upsert by Type+Profile
24+
updated := false
25+
for i := range pc.Status.PtpStatus.Conditions {
26+
c := &pc.Status.PtpStatus.Conditions[i]
27+
if c.Type == cond.Type && c.Profile == cond.Profile {
28+
*c = cond
29+
updated = true
30+
break
31+
}
32+
}
33+
if !updated {
34+
pc.Status.PtpStatus.Conditions = append(pc.Status.PtpStatus.Conditions, cond)
35+
}
36+
37+
// enforce max history
38+
const maxConditions = 100
39+
if n := len(pc.Status.PtpStatus.Conditions); n > maxConditions {
40+
pc.Status.PtpStatus.Conditions = pc.Status.PtpStatus.Conditions[n-maxConditions:]
41+
}
42+
43+
_, err = cs.PtpV1().PtpConfigs(namespace).UpdateStatus(ctx, pc, metav1.UpdateOptions{})
44+
if err != nil {
45+
// retry on conflict or transient errors
46+
return false, nil
47+
}
48+
return true, nil
49+
})
50+
}

0 commit comments

Comments
 (0)