Skip to content

Commit 40e1f03

Browse files
committed
OCPBUGS-54780: Fix issue where console operator orphans custom logo configmaps in openshift-console namespace
1 parent a350e28 commit 40e1f03

File tree

3 files changed

+99
-49
lines changed

3 files changed

+99
-49
lines changed

pkg/console/operator/operator.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,9 @@ type trackables struct {
102102
// used to keep track of OLM capability
103103
isOLMDisabled bool
104104
// track organization ID and mail
105-
organizationID string
106-
accountMail string
105+
organizationID string
106+
accountMail string
107+
customLogoConfigMaps []string
107108
}
108109

109110
func NewConsoleOperator(

pkg/console/operator/sync_custom_logo_config_maps.go

Lines changed: 81 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package operator
22

33
import (
44
"fmt"
5+
"slices"
56

67
// kube
78
"k8s.io/klog/v2"
@@ -25,62 +26,91 @@ func (co *consoleOperator) SyncCustomLogos(operatorConfig *operatorv1.Console) (
2526
aggregatedError error
2627
err error
2728
reason string
29+
newSyncedLogos []string
2830
)
2931
for _, logo := range operatorConfig.Spec.Customization.Logos {
3032
for _, theme := range logo.Themes {
3133
logoToSync := theme.Source.ConfigMap
32-
err, reason = co.updateCustomLogoSyncSource(logoToSync)
33-
if err != nil {
34+
if err, reason = co.validateCustomLogo(logoToSync); err != nil {
3435
if aggregatedError == nil {
35-
aggregatedError = fmt.Errorf("One or more errors were encountered while syncing custom logos:\n - %v, %s", logoToSync, err.Error())
36+
aggregatedError = fmt.Errorf("error syncing custom logos: - Invalid config: %v, %s", logoToSync, err.Error())
3637
} else {
37-
aggregatedError = fmt.Errorf("%s\n - %v, %s", aggregatedError.Error(), logoToSync, err.Error())
38+
aggregatedError = fmt.Errorf("%s - %v, %s", aggregatedError.Error(), logoToSync, err.Error())
3839
}
40+
} else {
41+
newSyncedLogos = append(newSyncedLogos, logoToSync.Name)
3942
}
4043
}
4144
}
4245
if aggregatedError != nil {
4346
return aggregatedError, reason
4447
}
45-
return nil, ""
48+
slices.Sort(newSyncedLogos)
49+
return co.updateCustomLogoSyncSources(newSyncedLogos)
4650
}
4751

4852
// TODO remove deprecated CustomLogoFile API
4953
func (co *consoleOperator) SyncCustomLogoConfigMap(operatorConfig *operatorv1.Console) (error, string) {
5054
var customLogoRef = operatorv1.ConfigMapFileReference(operatorConfig.Spec.Customization.CustomLogoFile)
51-
return co.updateCustomLogoSyncSource(&customLogoRef)
55+
klog.V(4).Infof("syncing customLogoFile, Name: %s, Key: %s", customLogoRef.Name, customLogoRef.Key)
56+
err, reason := co.validateCustomLogo(&customLogoRef)
57+
if err != nil {
58+
klog.V(4).Infof("failed to sync customLogoFile, %v", err)
59+
return err, reason
60+
}
61+
return co.updateCustomLogoSyncSources([]string{customLogoRef.Name})
5262
}
5363

5464
// on each pass of the operator sync loop, we need to check the
55-
// operator config for a custom logo. If this has been set, then
56-
// we notify the resourceSyncer that it needs to start watching this
57-
// configmap in its own sync loop. Note that the resourceSyncer's actual
65+
// operator config for custom logos. If this has been set, then
66+
// we notify the resourceSyncer that it needs to start watching the associated
67+
// configmaps in its own sync loop. Note that the resourceSyncer's actual
5868
// sync loop will run later. Our operator is waiting to receive
59-
// the copied configmap into the console namespace for a future
69+
// the copied configmaps into the console namespace for a future
6070
// sync loop to mount into the console deployment.
61-
func (c *consoleOperator) updateCustomLogoSyncSource(cmRef *operatorv1.ConfigMapFileReference) (error, string) {
62-
// validate first, to avoid a broken volume mount & a crashlooping console
63-
err, reason := c.validateCustomLogo(cmRef)
64-
if err != nil {
65-
return err, reason
71+
func (co *consoleOperator) updateCustomLogoSyncSources(configMapNames []string) (error, string) {
72+
klog.V(4).Info("syncing custom logo configmap resources")
73+
klog.V(4).Infof("%#v", configMapNames)
74+
75+
errors := []string{}
76+
if len(co.trackables.customLogoConfigMaps) > 0 {
77+
klog.V(4).Info("unsyncing custom logo configmap resources from previous sync loop...")
78+
for _, configMapName := range co.trackables.customLogoConfigMaps {
79+
err := co.updateCustomLogoSyncSource(configMapName, true)
80+
if err != nil {
81+
errors = append(errors, err.Error())
82+
}
83+
}
84+
85+
if len(errors) > 0 {
86+
msg := fmt.Sprintf("error syncing custom logo configmap resources\n%v", errors)
87+
klog.V(4).Info(msg)
88+
return fmt.Errorf(msg), "FailedResourceSync"
89+
}
6690
}
6791

68-
source := resourcesynccontroller.ResourceLocation{}
69-
logoConfigMapName := cmRef.Name
92+
if len(configMapNames) > 0 {
93+
// If the new list of synced configmaps is different than the last sync, we need to update the
94+
// resource syncer with the new list, and re
95+
klog.V(4).Infof("syncing new custom logo configmap resources...")
96+
for _, configMapName := range configMapNames {
97+
err := co.updateCustomLogoSyncSource(configMapName, false)
98+
if err != nil {
99+
errors = append(errors, err.Error())
100+
}
101+
}
70102

71-
if logoConfigMapName != "" {
72-
source.Name = logoConfigMapName
73-
source.Namespace = api.OpenShiftConfigNamespace
74-
}
75-
// if no custom logo provided, sync an empty source to delete
76-
err = c.resourceSyncer.SyncConfigMap(
77-
resourcesynccontroller.ResourceLocation{Namespace: api.OpenShiftConsoleNamespace, Name: cmRef.Name},
78-
source,
79-
)
80-
if err != nil {
81-
return err, "FailedResourceSync"
103+
if len(errors) > 0 {
104+
msg := fmt.Sprintf("error syncing custom logo configmap resources:\n%v", errors)
105+
klog.V(4).Infof(msg)
106+
return fmt.Errorf(msg), "FailedResourceSync"
107+
}
82108
}
83109

110+
klog.V(4).Info("saving synced custom logo configmap resources for next loop")
111+
co.trackables.customLogoConfigMaps = configMapNames
112+
113+
klog.V(4).Info("done")
84114
return nil, ""
85115
}
86116

@@ -89,13 +119,13 @@ func (co *consoleOperator) validateCustomLogo(logoFileRef *operatorv1.ConfigMapF
89119
logoImageKey := logoFileRef.Key
90120

91121
if (len(logoConfigMapName) == 0) != (len(logoImageKey) == 0) {
92-
klog.V(4).Infoln("custom logo filename or key have not been set")
122+
klog.V(4).Info("custom logo filename or key have not been set")
93123
return customerrors.NewCustomLogoError("either custom logo filename or key have not been set"), "KeyOrFilenameInvalid"
94124
}
95125

96126
// fine if nothing set, but don't mount it
97127
if len(logoConfigMapName) == 0 {
98-
klog.V(4).Infoln("no custom logo configured")
128+
klog.V(4).Info("no custom logo configured")
99129
return nil, ""
100130
}
101131

@@ -111,10 +141,30 @@ func (co *consoleOperator) validateCustomLogo(logoFileRef *operatorv1.ConfigMapF
111141
_, imageDataFound = logoConfigMap.Data[logoImageKey]
112142
}
113143
if !imageDataFound {
114-
klog.V(4).Infoln("custom logo file exists but no image provided")
144+
klog.V(4).Info("custom logo file exists but no image provided")
115145
return customerrors.NewCustomLogoError("custom logo file exists but no image provided"), "NoImageProvided"
116146
}
117147

118148
klog.V(4).Infof("custom logo %s ok to mount", logoConfigMapName)
119149
return nil, ""
120150
}
151+
152+
func (co *consoleOperator) updateCustomLogoSyncSource(targetName string, unsync bool) error {
153+
source := resourcesynccontroller.ResourceLocation{}
154+
if !unsync {
155+
source.Name = targetName
156+
source.Namespace = api.OpenShiftConfigNamespace
157+
}
158+
159+
target := resourcesynccontroller.ResourceLocation{
160+
Namespace: api.OpenShiftConsoleNamespace,
161+
Name: targetName,
162+
}
163+
164+
if unsync {
165+
klog.V(4).Infof("unsyncing %s", targetName)
166+
} else {
167+
klog.V(4).Infof("syncing %s", targetName)
168+
}
169+
return co.resourceSyncer.SyncConfigMap(target, source)
170+
}

test/e2e/brand_customization_test.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -115,22 +115,21 @@ func TestCustomBrand(t *testing.T) {
115115
t.Fatalf("could not clear customizations from operator config (%s)", err)
116116
}
117117

118-
// TODO re-enable this check once https://issues.redhat.com/browse/OCPBUGS-54780 is fixed
119-
// t.Logf("ensure that the %s configmap is no longer synced to 'openshift-console' namespace", suite.customLogoConfigMapName)
120-
// err = wait.Poll(pollFrequency, pollStandardMax, func() (stop bool, err error) {
121-
// _, err = framework.GetCustomLogoConfigMap(client, suite.customLogoConfigMapName)
122-
// if apiErrors.IsNotFound(err) {
123-
// return true, nil
124-
// }
125-
// if err != nil {
126-
// return false, err
127-
// }
128-
// // Try until timeout
129-
// return false, nil
130-
// })
131-
// if err != nil {
132-
// t.Fatalf("timed out checking for configmap '%s' in 'openshift-console'", suite.customLogoConfigMapName)
133-
// }
118+
t.Logf("ensure that the %s configmap is no longer synced to 'openshift-console' namespace", suite.customLogoConfigMapName)
119+
err = wait.Poll(pollFrequency, pollStandardMax, func() (stop bool, err error) {
120+
_, err = framework.GetCustomLogoConfigMap(client, suite.customLogoConfigMapName)
121+
if apiErrors.IsNotFound(err) {
122+
return true, nil
123+
}
124+
if err != nil {
125+
return false, err
126+
}
127+
// Try until timeout
128+
return false, nil
129+
})
130+
if err != nil {
131+
t.Fatalf("configmap '%s' was orphaned in 'openshift-console' namespace", suite.customLogoConfigMapName)
132+
}
134133
}
135134
}
136135

0 commit comments

Comments
 (0)