Skip to content

Commit cf3db27

Browse files
committed
refactor: prepare reconciliation infrastructure with improved status handling and event filtering
- Refactor status handling from strings to structured conditions (StagingCondition, TriggerCondition) - Add dedicated status files with condition constants for type safety - Add SetStatus helper methods for cleaner status updates - Implement event filtering with predicates to focus reconciliation on relevant changes: - GenerationChangedPredicate for spec changes - AnnotationChangedPredicate for annotation updates - Add RBAC permissions for batch/jobs resources
1 parent 72d877a commit cf3db27

File tree

13 files changed

+305
-26
lines changed

13 files changed

+305
-26
lines changed

Makefile

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ help: ## Display this help.
77

88
##@ Pipeline Forge Development
99

10-
.PHONY: test
11-
test: test-operator ## Run Pipeline Forge tests
1210

1311
.PHONY: dev-up
1412
dev-up: ## Start development environment with docker-compose (dev/)

operator/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and Cust
2929

3030
.PHONY: generate
3131
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
32-
$(CONTROLLER_GEN) object:headerFile="../hack/boilerplate.go.txt" paths="./..."
32+
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
3333

3434
.PHONY: fmt
3535
fmt: ## Run go fmt against code.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package v1alpha1
2+
3+
type StagingCondition string
4+
5+
const (
6+
StagingStatusCompleted StagingCondition = "Completed"
7+
StagingConditionFailed StagingCondition = "Failed"
8+
StagingConditionPending StagingCondition = "Pending"
9+
StagingConditionRunning StagingCondition = "Running"
10+
StagingConditionSuspended StagingCondition = "Suspended"
11+
StagingConditionReady StagingCondition = "Ready"
12+
StagingConditionInitiating StagingCondition = "Initiating"
13+
)

operator/api/v1alpha1/staging_types.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ type StagingSpec struct {
220220
// +kubebuilder:object:generate=true
221221
type InternalStatus struct {
222222
// Status of the associated staging object (e.g., Complete, Running, Failed, Pending, Unknown).
223-
Status string `json:"status,omitempty"`
223+
Status *StagingCondition `json:"status,omitempty"`
224224

225225
// Message provides additional information or error messages about the step status.
226226
Message string `json:"message,omitempty"`
@@ -260,7 +260,7 @@ type InternalStatus struct {
260260
type StagingStatus struct {
261261
// Status is the status of the Staging (e.g., Deployed, Failed, Pending, Running).
262262
// +kubebuilder:validation:Enum=Pending;Running;Completed;Failed;Suspended;Unknown
263-
Status StatusType `json:"status,omitempty"`
263+
Status *StagingCondition `json:"status,omitempty"`
264264

265265
// ObservedGeneration is the most recent generation observed by the controller.
266266
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
@@ -306,6 +306,11 @@ type StagingList struct {
306306
Items []Staging `json:"items"`
307307
}
308308

309+
// SetStatus is a helper function to set the staging status condition
310+
func (s *StagingStatus) SetStatus(condition StagingCondition) {
311+
s.Status = &condition
312+
}
313+
309314
func init() {
310315
SchemeBuilder.Register(&Staging{}, &StagingList{})
311316
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package v1alpha1
2+
3+
type TriggerCondition string
4+
5+
const (
6+
TriggerStatusCompleted TriggerCondition = "Completed"
7+
TriggerConditionFailed TriggerCondition = "Failed"
8+
TriggerConditionPending TriggerCondition = "Pending"
9+
TriggerConditionRunning TriggerCondition = "Running"
10+
TriggerConditionSuspended TriggerCondition = "Suspended"
11+
TriggerConditionReady TriggerCondition = "Ready"
12+
TriggerConditionInitiating TriggerCondition = "Initiating"
13+
)

operator/api/v1alpha1/trigger_types.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,10 @@ type TriggerSpec struct {
175175
// +kubebuilder:object:generate=true
176176
type TriggerStatus struct {
177177
// Status is the status of the Trigger (e.g., Deployed, Failed, Pending, Running).
178-
// +kubebuilder:validation:Enum=Pending;Running;Completed;Failed;Suspended;Unknown
179-
Status string `json:"status,omitempty"`
178+
Status *TriggerCondition `json:"status,omitempty"`
179+
180+
// ObservedGeneration is the most recent generation observed by the controller.
181+
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
180182

181183
// Conditions represent the latest available observations of the trigger's state.
182184
// Examples: Ready, Failed, CooldownActive
@@ -240,7 +242,7 @@ type Trigger struct {
240242
Spec TriggerSpec `json:"spec"`
241243

242244
// status defines the observed state of Trigger
243-
Status StatusType `json:"status,omitempty,omitzero"`
245+
Status TriggerStatus `json:"status,omitempty,omitzero"`
244246
}
245247

246248
// +kubebuilder:object:root=true
@@ -252,6 +254,11 @@ type TriggerList struct {
252254
Items []Trigger `json:"items"`
253255
}
254256

257+
// SetStatus is a helper function to set the trigger status condition
258+
func (t *TriggerStatus) SetStatus(condition TriggerCondition) {
259+
t.Status = &condition
260+
}
261+
255262
func init() {
256263
SchemeBuilder.Register(&Trigger{}, &TriggerList{})
257264
}

operator/api/v1alpha1/zz_generated.deepcopy.go

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

operator/config/crd/bases/core.pipeline-forge.io_triggers.yaml

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,129 @@ spec:
251251
type: object
252252
status:
253253
description: status defines the observed state of Trigger
254-
type: string
254+
properties:
255+
attempts:
256+
description: Attempts tracks the number of times this step has been
257+
attempted.
258+
format: int32
259+
type: integer
260+
conditions:
261+
description: |-
262+
Conditions represent the latest available observations of the trigger's state.
263+
Examples: Ready, Failed, CooldownActive
264+
items:
265+
description: Condition contains details for one aspect of the current
266+
state of this API Resource.
267+
properties:
268+
lastTransitionTime:
269+
description: |-
270+
lastTransitionTime is the last time the condition transitioned from one status to another.
271+
This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
272+
format: date-time
273+
type: string
274+
message:
275+
description: |-
276+
message is a human readable message indicating details about the transition.
277+
This may be an empty string.
278+
maxLength: 32768
279+
type: string
280+
observedGeneration:
281+
description: |-
282+
observedGeneration represents the .metadata.generation that the condition was set based upon.
283+
For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date
284+
with respect to the current state of the instance.
285+
format: int64
286+
minimum: 0
287+
type: integer
288+
reason:
289+
description: |-
290+
reason contains a programmatic identifier indicating the reason for the condition's last transition.
291+
Producers of specific condition types may define expected values and meanings for this field,
292+
and whether the values are considered a guaranteed API.
293+
The value should be a CamelCase string.
294+
This field may not be empty.
295+
maxLength: 1024
296+
minLength: 1
297+
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
298+
type: string
299+
status:
300+
description: status of the condition, one of True, False, Unknown.
301+
enum:
302+
- "True"
303+
- "False"
304+
- Unknown
305+
type: string
306+
type:
307+
description: type of condition in CamelCase or in foo.example.com/CamelCase.
308+
maxLength: 316
309+
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
310+
type: string
311+
required:
312+
- lastTransitionTime
313+
- message
314+
- reason
315+
- status
316+
- type
317+
type: object
318+
type: array
319+
cooldownUntil:
320+
description: CooldownUntil is the next eligible time this trigger
321+
can fire, based on Cooldown setting.
322+
format: date-time
323+
type: string
324+
failedAttempts:
325+
description: FailedAttempts tracks the number of failed attempts.
326+
format: int32
327+
type: integer
328+
lastAttemptTime:
329+
description: LastAttemptTime is the timestamp of the last attempt.
330+
format: date-time
331+
type: string
332+
lastCheckTime:
333+
description: LastCheckTime is the last time the controller evaluated
334+
whether to trigger.
335+
format: date-time
336+
type: string
337+
lastFailureTime:
338+
description: LastFailureTime is the timestamp of the last failure.
339+
format: date-time
340+
type: string
341+
lastRunJobName:
342+
description: LastRunJobName is the name of the last Kubernetes Job
343+
created by this trigger.
344+
type: string
345+
lastTriggeredTime:
346+
description: LastTriggeredTime is the last time this trigger successfully
347+
resulted in a pipeline activation.
348+
format: date-time
349+
type: string
350+
maxRetries:
351+
description: MaxRetries defines the maximum number of retries allowed.
352+
format: int32
353+
type: integer
354+
message:
355+
description: Message provides human-readable information about the
356+
trigger status or last evaluation.
357+
type: string
358+
observedGeneration:
359+
description: ObservedGeneration is the most recent generation observed
360+
by the controller.
361+
format: int64
362+
type: integer
363+
retryCount:
364+
description: RetryCount tracks the number of retries for the current
365+
attempt.
366+
format: int32
367+
type: integer
368+
status:
369+
description: Status is the status of the Trigger (e.g., Deployed,
370+
Failed, Pending, Running).
371+
type: string
372+
successfulAttempts:
373+
description: SuccessfulAttempts tracks the number of successful attempts.
374+
format: int32
375+
type: integer
376+
type: object
255377
required:
256378
- spec
257379
type: object

operator/config/rbac/role.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ kind: ClusterRole
44
metadata:
55
name: manager-role
66
rules:
7+
- apiGroups:
8+
- batch
9+
resources:
10+
- jobs
11+
verbs:
12+
- get
13+
- list
14+
- watch
715
- apiGroups:
816
- core.pipeline-forge.io
917
resources:

operator/hack/boilerplate.go.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
Copyright 2025 Daniel Blei.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/

0 commit comments

Comments
 (0)