Skip to content

Commit 98f42da

Browse files
committed
wip implement .spec.progressDeadlineMinutes
1 parent dc20dfb commit 98f42da

File tree

17 files changed

+347
-6
lines changed

17 files changed

+347
-6
lines changed

api/v1/clusterextension_types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,17 @@ type ClusterExtensionSpec struct {
107107
//
108108
// +optional
109109
Config *ClusterExtensionConfig `json:"config,omitempty"`
110+
111+
// progressDeadlineMinutes is an optional field that defines the maximum period
112+
// of time in minutes after which an installation should be considered failed and
113+
// require manual intervention. This functionality is disabled when no value
114+
// is provided. The minimum period is 10 minutes, and the maximum is 720 minutes (12 hours).
115+
//
116+
// +kubebuilder:validation:Minimum:=10
117+
// +kubebuilder:validation:Maximum:=720
118+
// +optional
119+
// <opcon:experimental>
120+
ProgressDeadlineMinutes int32 `json:"progressDeadlineMinutes,omitempty"`
110121
}
111122

112123
const SourceTypeCatalog = "Catalog"

api/v1/clusterextensionrevision_types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ type ClusterExtensionRevisionSpec struct {
8787
// +listMapKey=name
8888
// +optional
8989
Phases []ClusterExtensionRevisionPhase `json:"phases,omitempty"`
90+
91+
// progressDeadlineMinutes is an optional field that defines the maximum period
92+
// of time in minutes after which an installation should be considered failed and
93+
// require manual intervention. This functionality is disabled when no value
94+
// is provided. The minimum period is 10 minutes, and the maximum is 720 minutes (12 hours).
95+
//
96+
// +kubebuilder:validation:Minimum:=10
97+
// +kubebuilder:validation:Maximum:=720
98+
// +optional
99+
// <opcon:experimental>
100+
ProgressDeadlineMinutes int32 `json:"progressDeadlineMinutes,omitempty"`
90101
}
91102

92103
// ClusterExtensionRevisionLifecycleState specifies the lifecycle state of the ClusterExtensionRevision.

api/v1/common_types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const (
3232
ReasonDeprecated = "Deprecated"
3333

3434
// Common reasons
35-
ReasonSucceeded = "Succeeded"
36-
ReasonFailed = "Failed"
35+
ReasonSucceeded = "Succeeded"
36+
ReasonFailed = "Failed"
37+
ReasonProgressDeadlineExceeded = "ProgressDeadlineExceeded"
3738
)

docs/api-reference/olmv1-api-reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ _Appears in:_
344344
| `source` _[SourceConfig](#sourceconfig)_ | source is required and selects the installation source of content for this ClusterExtension.<br />Set the sourceType field to perform the selection.<br />Catalog is currently the only implemented sourceType.<br />Setting sourceType to "Catalog" requires the catalog field to also be defined.<br />Below is a minimal example of a source definition (in yaml):<br />source:<br /> sourceType: Catalog<br /> catalog:<br /> packageName: example-package | | Required: \{\} <br /> |
345345
| `install` _[ClusterExtensionInstallConfig](#clusterextensioninstallconfig)_ | install is optional and configures installation options for the ClusterExtension,<br />such as the pre-flight check configuration. | | |
346346
| `config` _[ClusterExtensionConfig](#clusterextensionconfig)_ | config is optional and specifies bundle-specific configuration.<br />Configuration is bundle-specific and a bundle may provide a configuration schema.<br />When not specified, the default configuration of the resolved bundle is used.<br />config is validated against a configuration schema provided by the resolved bundle. If the bundle does not provide<br />a configuration schema the bundle is deemed to not be configurable. More information on how<br />to configure bundles can be found in the OLM documentation associated with your current OLM version. | | |
347+
| `progressDeadlineMinutes` _integer_ | progressDeadlineMinutes is an optional field that defines the maximum period<br />of time in minutes after which an installation should be considered failed and<br />require manual intervention. This functionality is disabled when no value<br />is provided. The minimum period is 10 minutes, and the maximum is 720 minutes (12 hours).<br /><opcon:experimental> | | Maximum: 720 <br />Minimum: 10 <br /> |
347348

348349

349350
#### ClusterExtensionStatus

helm/olmv1/base/operator-controller/crd/experimental/olm.operatorframework.io_clusterextensionrevisions.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,16 @@ spec:
166166
x-kubernetes-validations:
167167
- message: phases is immutable
168168
rule: self == oldSelf || oldSelf.size() == 0
169+
progressDeadlineMinutes:
170+
description: |-
171+
progressDeadlineMinutes is an optional field that defines the maximum period
172+
of time in minutes after which an installation should be considered failed and
173+
require manual intervention. This functionality is disabled when no value
174+
is provided. The minimum period is 10 minutes, and the maximum is 720 minutes (12 hours).
175+
format: int32
176+
maximum: 720
177+
minimum: 10
178+
type: integer
169179
revision:
170180
description: |-
171181
revision is a required, immutable sequence number representing a specific revision

helm/olmv1/base/operator-controller/crd/experimental/olm.operatorframework.io_clusterextensions.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,16 @@ spec:
165165
rule: self == oldSelf
166166
- message: namespace must be a valid DNS1123 label
167167
rule: self.matches("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")
168+
progressDeadlineMinutes:
169+
description: |-
170+
progressDeadlineMinutes is an optional field that defines the maximum period
171+
of time in minutes after which an installation should be considered failed and
172+
require manual intervention. This functionality is disabled when no value
173+
is provided. The minimum period is 10 minutes, and the maximum is 720 minutes (12 hours).
174+
format: int32
175+
maximum: 720
176+
minimum: 10
177+
type: integer
168178
serviceAccount:
169179
description: |-
170180
serviceAccount specifies a ServiceAccount used to perform all interactions with the cluster

internal/operator-controller/applier/boxcutter.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ func (r *SimpleRevisionGenerator) buildClusterExtensionRevision(
191191
annotations[labels.ServiceAccountNameKey] = ext.Spec.ServiceAccount.Name
192192
annotations[labels.ServiceAccountNamespaceKey] = ext.Spec.Namespace
193193

194-
return &ocv1.ClusterExtensionRevision{
194+
cer := &ocv1.ClusterExtensionRevision{
195195
ObjectMeta: metav1.ObjectMeta{
196196
Annotations: annotations,
197197
Labels: map[string]string{
@@ -206,6 +206,10 @@ func (r *SimpleRevisionGenerator) buildClusterExtensionRevision(
206206
Phases: PhaseSort(objects),
207207
},
208208
}
209+
if p := ext.Spec.ProgressDeadlineMinutes; p > 0 {
210+
cer.Spec.ProgressDeadlineMinutes = p
211+
}
212+
return cer
209213
}
210214

211215
// BoxcutterStorageMigrator migrates ClusterExtensions from Helm-based storage to

internal/operator-controller/conditionsets/conditionsets.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ var ConditionReasons = []string{
4141
ocv1.ReasonRetrying,
4242
ocv1.ReasonAbsent,
4343
ocv1.ReasonRollingOut,
44+
ocv1.ReasonProgressDeadlineExceeded,
4445
}

internal/operator-controller/controllers/clusterextensionrevision_controller.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"errors"
99
"fmt"
1010
"strings"
11+
"sync"
1112
"time"
1213

1314
appsv1 "k8s.io/api/apps/v1"
@@ -43,9 +44,10 @@ const (
4344
// ClusterExtensionRevisionReconciler actions individual snapshots of ClusterExtensions,
4445
// as part of the boxcutter integration.
4546
type ClusterExtensionRevisionReconciler struct {
46-
Client client.Client
47-
RevisionEngineFactory RevisionEngineFactory
48-
TrackingCache trackingCache
47+
Client client.Client
48+
RevisionEngineFactory RevisionEngineFactory
49+
TrackingCache trackingCache
50+
progressionRequeueOnce sync.Map
4951
}
5052

5153
type trackingCache interface {
@@ -74,6 +76,17 @@ func (c *ClusterExtensionRevisionReconciler) Reconcile(ctx context.Context, req
7476
reconciledRev := existingRev.DeepCopy()
7577
res, reconcileErr := c.reconcile(ctx, reconciledRev)
7678

79+
if pd := existingRev.Spec.ProgressDeadlineMinutes; pd > 0 {
80+
if cnd := meta.FindStatusCondition(reconciledRev.Status.Conditions, ocv1.ClusterExtensionRevisionTypeProgressing); cnd != nil && cnd.Status == metav1.ConditionTrue && cnd.Reason != ocv1.ReasonSucceeded {
81+
timeout := time.Duration(pd) * time.Minute
82+
if time.Since(existingRev.CreationTimestamp.Time) > timeout {
83+
markAsNotProgressing(reconciledRev, ocv1.ReasonProgressDeadlineExceeded, fmt.Sprintf("Revision has not rolled out for %d minutes.", pd))
84+
// reset any errors that may have occurred during reconciliation and stop any further reconciliation due to the reached timeout
85+
reconcileErr = nil
86+
res = ctrl.Result{}
87+
}
88+
}
89+
}
7790
// Do checks before any Update()s, as Update() may modify the resource structure!
7891
updateStatus := !equality.Semantic.DeepEqual(existingRev.Status, reconciledRev.Status)
7992

@@ -92,6 +105,10 @@ func (c *ClusterExtensionRevisionReconciler) Reconcile(ctx context.Context, req
92105
}
93106
}
94107

108+
if _, found := c.progressionRequeueOnce.Load(existingRev.GetUID()); !found && reconcileErr == nil && existingRev.Spec.ProgressDeadlineMinutes > 0 {
109+
c.progressionRequeueOnce.Store(existingRev.GetUID(), true)
110+
res = ctrl.Result{RequeueAfter: time.Duration(existingRev.Spec.ProgressDeadlineMinutes) * time.Minute}
111+
}
95112
return res, reconcileErr
96113
}
97114

manifests/experimental-e2e.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,16 @@ spec:
778778
x-kubernetes-validations:
779779
- message: phases is immutable
780780
rule: self == oldSelf || oldSelf.size() == 0
781+
progressDeadlineMinutes:
782+
description: |-
783+
progressDeadlineMinutes is an optional field that defines the maximum period
784+
of time in minutes after which an installation should be considered failed and
785+
require manual intervention. This functionality is disabled when no value
786+
is provided. The minimum period is 10 minutes, and the maximum is 720 minutes (12 hours).
787+
format: int32
788+
maximum: 720
789+
minimum: 10
790+
type: integer
781791
revision:
782792
description: |-
783793
revision is a required, immutable sequence number representing a specific revision
@@ -1052,6 +1062,16 @@ spec:
10521062
rule: self == oldSelf
10531063
- message: namespace must be a valid DNS1123 label
10541064
rule: self.matches("^[a-z0-9]([-a-z0-9]*[a-z0-9])?$")
1065+
progressDeadlineMinutes:
1066+
description: |-
1067+
progressDeadlineMinutes is an optional field that defines the maximum period
1068+
of time in minutes after which an installation should be considered failed and
1069+
require manual intervention. This functionality is disabled when no value
1070+
is provided. The minimum period is 10 minutes, and the maximum is 720 minutes (12 hours).
1071+
format: int32
1072+
maximum: 720
1073+
minimum: 10
1074+
type: integer
10551075
serviceAccount:
10561076
description: |-
10571077
serviceAccount specifies a ServiceAccount used to perform all interactions with the cluster

0 commit comments

Comments
 (0)