Skip to content

Commit d0ccd84

Browse files
committed
chore(catalog): add ClusterOperator status for catalog operator
previously we were only reporting OLM status
1 parent 9ee66d0 commit d0ccd84

File tree

6 files changed

+249
-196
lines changed

6 files changed

+249
-196
lines changed

cmd/catalog/main.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ import (
88
"strings"
99
"time"
1010

11+
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
12+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
13+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus"
1114
"github.com/prometheus/client_golang/prometheus/promhttp"
1215
log "github.com/sirupsen/logrus"
1316
v1 "k8s.io/api/core/v1"
17+
"k8s.io/client-go/tools/clientcmd"
1418

1519
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog"
1620
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/signals"
@@ -22,6 +26,7 @@ const (
2226
defaultWakeupInterval = 15 * time.Minute
2327
defaultCatalogNamespace = "openshift-operator-lifecycle-manager"
2428
defaultConfigMapServerImage = "quay.io/operatorframework/configmap-operator-registry:latest"
29+
defaultOperatorName = ""
2530
)
2631

2732
// config flags defined globally so that they appear on the test binary as well
@@ -41,6 +46,9 @@ var (
4146
configmapServerImage = flag.String(
4247
"configmapServerImage", defaultConfigMapServerImage, "the image to use for serving the operator registry api for a configmap")
4348

49+
writeStatusName = flag.String(
50+
"writeStatusName", defaultOperatorName, "ClusterOperator name in which to write status, set to \"\" to disable.")
51+
4452
debug = flag.Bool(
4553
"debug", false, "use debug log level")
4654

@@ -87,6 +95,17 @@ func main() {
8795
}
8896
logger.Infof("log level %s", logger.Level)
8997

98+
// create a config client for operator status
99+
config, err := clientcmd.BuildConfigFromFlags("", *kubeConfigPath)
100+
if err != nil {
101+
log.Fatalf("error configuring client: %s", err.Error())
102+
}
103+
configClient, err := configv1client.NewForConfig(config)
104+
if err != nil {
105+
log.Fatalf("error configuring client: %s", err.Error())
106+
}
107+
opClient := operatorclient.NewClientFromConfig(*kubeConfigPath, logger)
108+
90109
// Create a new instance of the operator.
91110
catalogOperator, err := catalog.NewOperator(*kubeConfigPath, logger, *wakeupInterval, *configmapServerImage, *catalogNamespace, namespaces...)
92111
if err != nil {
@@ -96,6 +115,12 @@ func main() {
96115
http.Handle("/metrics", promhttp.Handler())
97116
go http.ListenAndServe(":8081", nil)
98117

99-
_, done, _ := catalogOperator.Run(stopCh)
118+
ready, done, sync := catalogOperator.Run(stopCh)
119+
<-ready
120+
121+
if *writeStatusName != "" {
122+
operatorstatus.MonitorClusterStatus(*writeStatusName, sync, stopCh, opClient, configClient)
123+
}
124+
100125
<-done
101126
}

cmd/olm/main.go

Lines changed: 3 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,16 @@ import (
55
"fmt"
66
"net/http"
77
"os"
8-
"reflect"
98
"strings"
109
"time"
1110

11+
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
12+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorstatus"
1213
"github.com/prometheus/client_golang/prometheus/promhttp"
1314
log "github.com/sirupsen/logrus"
1415
v1 "k8s.io/api/core/v1"
15-
k8serrors "k8s.io/apimachinery/pkg/api/errors"
16-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17-
"k8s.io/apimachinery/pkg/runtime/schema"
18-
"k8s.io/apimachinery/pkg/util/wait"
19-
"k8s.io/client-go/discovery"
2016
"k8s.io/client-go/tools/clientcmd"
2117

22-
configv1 "github.com/openshift/api/config/v1"
23-
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
2418
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client"
2519
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install"
2620
"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm"
@@ -132,194 +126,8 @@ func main() {
132126
<-ready
133127

134128
if *writeStatusName != "" {
135-
monitorClusterStatus(sync, stopCh, opClient, configClient)
129+
operatorstatus.MonitorClusterStatus(*writeStatusName, sync, stopCh, opClient, configClient)
136130
}
137131

138132
<-done
139133
}
140-
141-
func monitorClusterStatus(syncCh chan error, stopCh <-chan struct{}, opClient operatorclient.ClientInterface, configClient configv1client.ConfigV1Interface) {
142-
var (
143-
syncs int
144-
successfulSyncs int
145-
hasClusterOperator bool
146-
)
147-
go wait.Until(func() {
148-
// slow poll until we see a cluster operator API, which could be never
149-
if !hasClusterOperator {
150-
opStatusGV := schema.GroupVersion{
151-
Group: "config.openshift.io",
152-
Version: "v1",
153-
}
154-
err := discovery.ServerSupportsVersion(opClient.KubernetesInterface().Discovery(), opStatusGV)
155-
if err != nil {
156-
log.Infof("ClusterOperator api not present, skipping update (%v)", err)
157-
time.Sleep(time.Minute)
158-
return
159-
}
160-
hasClusterOperator = true
161-
}
162-
163-
// Sample the sync channel and see whether we're successfully retiring syncs as a
164-
// proxy for "working" (we can't know when we hit level, but we can at least verify
165-
// we are seeing some syncs succeeding). Once we observe at least one successful
166-
// sync we can begin reporting available and level.
167-
select {
168-
case err, ok := <-syncCh:
169-
if !ok {
170-
// syncCh should only close if the Run() loop exits
171-
time.Sleep(5 * time.Second)
172-
log.Fatalf("Status sync channel closed but process did not exit in time")
173-
}
174-
syncs++
175-
if err == nil {
176-
successfulSyncs++
177-
}
178-
// grab any other sync events that have accumulated
179-
for len(syncCh) > 0 {
180-
if err := <-syncCh; err == nil {
181-
successfulSyncs++
182-
}
183-
syncs++
184-
}
185-
// if we haven't yet accumulated enough syncs, wait longer
186-
// TODO: replace these magic numbers with a better measure of syncs across all queueInformers
187-
if successfulSyncs < 5 || syncs < 10 {
188-
log.Printf("Waiting to observe more successful syncs")
189-
return
190-
}
191-
}
192-
193-
// create the cluster operator in an initial state if it does not exist
194-
existing, err := configClient.ClusterOperators().Get(*writeStatusName, metav1.GetOptions{})
195-
if k8serrors.IsNotFound(err) {
196-
log.Info("Existing operator status not found, creating")
197-
created, createErr := configClient.ClusterOperators().Create(&configv1.ClusterOperator{
198-
ObjectMeta: metav1.ObjectMeta{
199-
Name: *writeStatusName,
200-
},
201-
Status: configv1.ClusterOperatorStatus{
202-
Conditions: []configv1.ClusterOperatorStatusCondition{
203-
configv1.ClusterOperatorStatusCondition{
204-
Type: configv1.OperatorProgressing,
205-
Status: configv1.ConditionTrue,
206-
Message: fmt.Sprintf("Installing %s", olmversion.OLMVersion),
207-
LastTransitionTime: metav1.Now(),
208-
},
209-
configv1.ClusterOperatorStatusCondition{
210-
Type: configv1.OperatorFailing,
211-
Status: configv1.ConditionFalse,
212-
LastTransitionTime: metav1.Now(),
213-
},
214-
configv1.ClusterOperatorStatusCondition{
215-
Type: configv1.OperatorAvailable,
216-
Status: configv1.ConditionFalse,
217-
LastTransitionTime: metav1.Now(),
218-
},
219-
},
220-
},
221-
})
222-
if createErr != nil {
223-
log.Errorf("Failed to create cluster operator: %v\n", createErr)
224-
return
225-
}
226-
existing = created
227-
err = nil
228-
}
229-
if err != nil {
230-
log.Errorf("Unable to retrieve cluster operator: %v", err)
231-
return
232-
}
233-
234-
// update the status with the appropriate state
235-
previousStatus := existing.Status.DeepCopy()
236-
switch {
237-
case successfulSyncs > 0:
238-
setOperatorStatusCondition(&existing.Status.Conditions, configv1.ClusterOperatorStatusCondition{
239-
Type: configv1.OperatorFailing,
240-
Status: configv1.ConditionFalse,
241-
})
242-
setOperatorStatusCondition(&existing.Status.Conditions, configv1.ClusterOperatorStatusCondition{
243-
Type: configv1.OperatorProgressing,
244-
Status: configv1.ConditionFalse,
245-
Message: fmt.Sprintf("Deployed %s", olmversion.OLMVersion),
246-
})
247-
setOperatorStatusCondition(&existing.Status.Conditions, configv1.ClusterOperatorStatusCondition{
248-
Type: configv1.OperatorAvailable,
249-
Status: configv1.ConditionTrue,
250-
})
251-
// we set the versions array when all the latest code is deployed and running - in this case,
252-
// the sync method is responsible for guaranteeing that happens before it returns nil
253-
if version := os.Getenv("RELEASE_VERSION"); len(version) > 0 {
254-
existing.Status.Versions = []configv1.OperandVersion{
255-
{
256-
Name: "operator",
257-
Version: version,
258-
},
259-
{
260-
Name: "operator-lifecycle-manager",
261-
Version: olmversion.OLMVersion,
262-
},
263-
}
264-
} else {
265-
existing.Status.Versions = nil
266-
}
267-
default:
268-
setOperatorStatusCondition(&existing.Status.Conditions, configv1.ClusterOperatorStatusCondition{
269-
Type: configv1.OperatorFailing,
270-
Status: configv1.ConditionTrue,
271-
Message: "Waiting for updates to take effect",
272-
})
273-
setOperatorStatusCondition(&existing.Status.Conditions, configv1.ClusterOperatorStatusCondition{
274-
Type: configv1.OperatorProgressing,
275-
Status: configv1.ConditionFalse,
276-
Message: fmt.Sprintf("Waiting to see update %s succeed", olmversion.OLMVersion),
277-
})
278-
// TODO: use % errors within a window to report available
279-
}
280-
281-
// update the status
282-
if !reflect.DeepEqual(previousStatus, &existing.Status) {
283-
if _, err := configClient.ClusterOperators().UpdateStatus(existing); err != nil {
284-
log.Errorf("Unable to update cluster operator status: %v", err)
285-
}
286-
}
287-
288-
// if we've reported success, we can sleep longer, otherwise we want to keep watching for
289-
// successful
290-
if successfulSyncs > 0 {
291-
time.Sleep(5 * time.Minute)
292-
}
293-
294-
}, 5*time.Second, stopCh)
295-
}
296-
297-
func setOperatorStatusCondition(conditions *[]configv1.ClusterOperatorStatusCondition, newCondition configv1.ClusterOperatorStatusCondition) {
298-
if conditions == nil {
299-
conditions = &[]configv1.ClusterOperatorStatusCondition{}
300-
}
301-
existingCondition := findOperatorStatusCondition(*conditions, newCondition.Type)
302-
if existingCondition == nil {
303-
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
304-
*conditions = append(*conditions, newCondition)
305-
return
306-
}
307-
308-
if existingCondition.Status != newCondition.Status {
309-
existingCondition.Status = newCondition.Status
310-
existingCondition.LastTransitionTime = newCondition.LastTransitionTime
311-
}
312-
313-
existingCondition.Reason = newCondition.Reason
314-
existingCondition.Message = newCondition.Message
315-
}
316-
317-
func findOperatorStatusCondition(conditions []configv1.ClusterOperatorStatusCondition, conditionType configv1.ClusterStatusConditionType) *configv1.ClusterOperatorStatusCondition {
318-
for i := range conditions {
319-
if conditions[i].Type == conditionType {
320-
return &conditions[i]
321-
}
322-
}
323-
324-
return nil
325-
}

deploy/chart/templates/0000_50_olm_07-catalog-operator.deployment.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ spec:
3535
{{- if .Values.catalog.commandArgs }}
3636
- {{ .Values.catalog.commandArgs }}
3737
{{- end }}
38+
{{- if .Values.writeStatusNameCatalog }}
39+
- -writeStatusName
40+
- {{ .Values.writeStatusNameCatalog }}
41+
{{- end }}
3842
image: {{ .Values.catalog.image.ref }}
3943
imagePullPolicy: {{ .Values.catalog.image.pullPolicy }}
4044
ports:

deploy/chart/templates/0000_50_olm_14-operatorstatus.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,13 @@ status:
77
versions:
88
- name: operator
99
version: "0.0.1-snapshot"
10+
---
11+
apiVersion: config.openshift.io/v1
12+
kind: ClusterOperator
13+
metadata:
14+
name: {{ .Values.writeStatusNameCatalog }}
15+
status:
16+
versions:
17+
- name: operator
18+
version: "0.0.1-snapshot"
1019
{{- end }}

deploy/ocp/values.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ catalog_namespace: openshift-operator-lifecycle-manager
55
operator_namespace: openshift-operators
66
imagestream: true
77
writeStatusName: operator-lifecycle-manager
8+
writeStatusNameCatalog: operator-lifecycle-manager-catalog
89
olm:
910
replicaCount: 1
1011
image:

0 commit comments

Comments
 (0)