Skip to content

Commit 9c82147

Browse files
committed
(feat) monitor package API server CSV progress
Communicate package API server deployment progress back to cluster version operator (cvo). Accomplish this goal by doing the following: - Add a label to package API server CSV so that we can identify it. olm.clusteroperator.name: operator-lifecycle-manager-packageserver - olm operator already watches all CSV(s). Add support to tap into these reconciliation notifications so that we can inspect all ClusterServiceVersion object(s). - Add logic so that we can identify the CSV we want. Any CSV having the label mentioned above is a matching CSV. Whenever we see a matching CSV, we find the relevant information and we send it to the monitor. - Write a monitor that runs forever. It receives the notification and updates the clusteroperator resource accordingly.
1 parent 0c5e011 commit 9c82147

File tree

9 files changed

+1379
-2
lines changed

9 files changed

+1379
-2
lines changed

cmd/olm/main.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ import (
2525
)
2626

2727
const (
28-
defaultWakeupInterval = 5 * time.Minute
29-
defaultOperatorName = ""
28+
defaultWakeupInterval = 5 * time.Minute
29+
defaultOperatorName = ""
30+
defaultPackageServerStatusName = ""
3031
)
3132

3233
// config flags defined globally so that they appear on the test binary as well
@@ -45,6 +46,9 @@ var (
4546
writeStatusName = flag.String(
4647
"writeStatusName", defaultOperatorName, "ClusterOperator name in which to write status, set to \"\" to disable.")
4748

49+
writePackageServerStatusName = flag.String(
50+
"writePackageServerStatusName", defaultPackageServerStatusName, "ClusterOperator name in which to write status for package API server, set to \"\" to disable.")
51+
4852
debug = flag.Bool(
4953
"debug", false, "use debug log level")
5054

@@ -170,5 +174,18 @@ func main() {
170174
operatorstatus.MonitorClusterStatus(*writeStatusName, op.AtLevel(), ctx.Done(), opClient, configClient)
171175
}
172176

177+
if *writePackageServerStatusName != "" {
178+
logger.Info("Initializing cluster operator monitor for package server")
179+
180+
names := *writePackageServerStatusName
181+
discovery := opClient.KubernetesInterface().Discovery()
182+
monitor, sender := operatorstatus.NewMonitor(names, logger, discovery, configClient)
183+
184+
handler := operatorstatus.NewCSVWatchNotificationHandler(logger, op.GetCSVSetGenerator(), op.GetReplaceFinder(), sender)
185+
op.RegisterCSVWatchNotification(handler)
186+
187+
go monitor.Run(op.Done())
188+
}
189+
173190
<-op.Done()
174191
}

pkg/lib/operatorstatus/builder.go

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
package operatorstatus
2+
3+
import (
4+
"reflect"
5+
6+
configv1 "github.com/openshift/api/config/v1"
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
"k8s.io/apimachinery/pkg/util/clock"
9+
)
10+
11+
// NewBuilder returns a builder for ClusterOperatorStatus.
12+
func NewBuilder(clock clock.Clock) *Builder {
13+
return &Builder{
14+
clock: clock,
15+
}
16+
}
17+
18+
// Builder helps build ClusterOperatorStatus with appropriate
19+
// ClusterOperatorStatusCondition and OperandVersion.
20+
type Builder struct {
21+
clock clock.Clock
22+
status *configv1.ClusterOperatorStatus
23+
}
24+
25+
// GetStatus returns the ClusterOperatorStatus built.
26+
func (b *Builder) GetStatus() *configv1.ClusterOperatorStatus {
27+
return b.status
28+
}
29+
30+
// WithProgressing sets an OperatorProgressing type condition.
31+
func (b *Builder) WithProgressing(status configv1.ConditionStatus, message string) *Builder {
32+
b.init()
33+
condition := &configv1.ClusterOperatorStatusCondition{
34+
Type: configv1.OperatorProgressing,
35+
Status: status,
36+
Message: message,
37+
LastTransitionTime: metav1.NewTime(b.clock.Now()),
38+
}
39+
40+
b.setCondition(condition)
41+
42+
return b
43+
}
44+
45+
// WithDegraded sets an OperatorDegraded type condition.
46+
func (b *Builder) WithDegraded(status configv1.ConditionStatus) *Builder {
47+
b.init()
48+
condition := &configv1.ClusterOperatorStatusCondition{
49+
Type: configv1.OperatorDegraded,
50+
Status: status,
51+
LastTransitionTime: metav1.NewTime(b.clock.Now()),
52+
}
53+
54+
b.setCondition(condition)
55+
56+
return b
57+
}
58+
59+
// WithAvailable sets an OperatorAvailable type condition.
60+
func (b *Builder) WithAvailable(status configv1.ConditionStatus, message string) *Builder {
61+
b.init()
62+
condition := &configv1.ClusterOperatorStatusCondition{
63+
Type: configv1.OperatorAvailable,
64+
Status: status,
65+
Message: message,
66+
LastTransitionTime: metav1.NewTime(b.clock.Now()),
67+
}
68+
69+
b.setCondition(condition)
70+
71+
return b
72+
}
73+
74+
// WithVersion adds the specific version into the status.
75+
func (b *Builder) WithVersion(name, version string) *Builder {
76+
b.init()
77+
78+
existing := b.findVersion(name)
79+
if existing != nil {
80+
existing.Version = version
81+
return b
82+
}
83+
84+
ov := configv1.OperandVersion{
85+
Name: name,
86+
Version: version,
87+
}
88+
b.status.Versions = append(b.status.Versions, ov)
89+
90+
return b
91+
}
92+
93+
// WithoutVersion removes the specified version from the existing status.
94+
func (b *Builder) WithoutVersion(name, version string) *Builder {
95+
b.init()
96+
97+
versions := make([]configv1.OperandVersion, 0)
98+
99+
for _, v := range b.status.Versions {
100+
if v.Name == name {
101+
continue
102+
}
103+
104+
versions = append(versions, v)
105+
}
106+
107+
b.status.Versions = versions
108+
return b
109+
}
110+
111+
// WithRelatedObject adds the reference specified to the RelatedObjects list.
112+
func (b *Builder) WithRelatedObject(group, resource, namespace, name string) *Builder {
113+
b.init()
114+
115+
reference := configv1.ObjectReference{
116+
Group: group,
117+
Resource: resource,
118+
Namespace: namespace,
119+
Name: name,
120+
}
121+
122+
b.setRelatedObject(reference)
123+
124+
return b
125+
}
126+
127+
// WithoutRelatedObject removes the reference specified from the RelatedObjects list.
128+
func (b *Builder) WithoutRelatedObject(group, resource, namespace, name string) *Builder {
129+
b.init()
130+
131+
reference := configv1.ObjectReference{
132+
Group: group,
133+
Resource: resource,
134+
Namespace: namespace,
135+
Name: name,
136+
}
137+
138+
related := make([]configv1.ObjectReference, 0)
139+
for i := range b.status.RelatedObjects {
140+
if reflect.DeepEqual(b.status.RelatedObjects[i], reference) {
141+
continue
142+
}
143+
144+
related = append(related, b.status.RelatedObjects[i])
145+
}
146+
147+
b.status.RelatedObjects = related
148+
return b
149+
}
150+
151+
func (b *Builder) init() {
152+
if b.status == nil {
153+
b.status = &configv1.ClusterOperatorStatus{
154+
Conditions: []configv1.ClusterOperatorStatusCondition{},
155+
Versions: []configv1.OperandVersion{},
156+
RelatedObjects: []configv1.ObjectReference{},
157+
}
158+
}
159+
}
160+
161+
func (b *Builder) findCondition(conditionType configv1.ClusterStatusConditionType) *configv1.ClusterOperatorStatusCondition {
162+
for i := range b.status.Conditions {
163+
if b.status.Conditions[i].Type == conditionType {
164+
return &b.status.Conditions[i]
165+
}
166+
}
167+
168+
return nil
169+
}
170+
171+
func (b *Builder) setCondition(condition *configv1.ClusterOperatorStatusCondition) {
172+
existing := b.findCondition(condition.Type)
173+
if existing == nil {
174+
b.status.Conditions = append(b.status.Conditions, *condition)
175+
return
176+
}
177+
178+
existing.Reason = condition.Reason
179+
existing.Message = condition.Message
180+
181+
if existing.Status != condition.Status {
182+
existing.Status = condition.Status
183+
existing.LastTransitionTime = condition.LastTransitionTime
184+
}
185+
}
186+
187+
func (b *Builder) findVersion(name string) *configv1.OperandVersion {
188+
for i := range b.status.Versions {
189+
if b.status.Versions[i].Name == name {
190+
return &b.status.Versions[i]
191+
}
192+
}
193+
194+
return nil
195+
}
196+
197+
func (b *Builder) setRelatedObject(reference configv1.ObjectReference) {
198+
for i := range b.status.RelatedObjects {
199+
if reflect.DeepEqual(b.status.RelatedObjects[i], reference) {
200+
return
201+
}
202+
}
203+
204+
b.status.RelatedObjects = append(b.status.RelatedObjects, reference)
205+
}

0 commit comments

Comments
 (0)