Skip to content

Commit 183e7e5

Browse files
authored
OCPBUGS-54780: Fix issue where console operator orphans custom logo configmaps in openshift-console namespace (#978)
* OCPBUGS-54780: Fix issue where console operator orphans custom logo configmaps in openshift-console namespace * improve debug logs for custom logo sync
1 parent b6949a5 commit 183e7e5

File tree

3 files changed

+106
-54
lines changed

3 files changed

+106
-54
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_v400.go

Lines changed: 88 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"net/url"
88
"os"
9+
"slices"
910
"strings"
1011

1112
// kube
@@ -559,30 +560,39 @@ func (co *consoleOperator) SyncCustomLogos(operatorConfig *operatorv1.Console) (
559560
aggregatedError error
560561
err error
561562
reason string
563+
newSyncedLogos []string
562564
)
563565
for _, logo := range operatorConfig.Spec.Customization.Logos {
564566
for _, theme := range logo.Themes {
565567
logoToSync := theme.Source.ConfigMap
566-
err, reason = co.UpdateCustomLogoSyncSource(logoToSync)
567-
if err != nil {
568+
if err, reason = co.ValidateCustomLogo(logoToSync); err != nil {
568569
if aggregatedError == nil {
569-
aggregatedError = fmt.Errorf("One or more errors were encountered while syncing custom logos:\n - %v, %s", logoToSync, err.Error())
570+
aggregatedError = fmt.Errorf("error syncing custom logos: - Invalid config: %v, %s", logoToSync, err.Error())
570571
} else {
571-
aggregatedError = fmt.Errorf("%s\n - %v, %s", aggregatedError.Error(), logoToSync, err.Error())
572+
aggregatedError = fmt.Errorf("%s - %v, %s", aggregatedError.Error(), logoToSync, err.Error())
572573
}
574+
} else {
575+
newSyncedLogos = append(newSyncedLogos, logoToSync.Name)
573576
}
574577
}
575578
}
576579
if aggregatedError != nil {
577580
return aggregatedError, reason
578581
}
579-
return nil, ""
582+
slices.Sort(newSyncedLogos)
583+
return co.UpdateCustomLogoSyncSources(newSyncedLogos)
580584
}
581585

582586
// TODO remove deprecated CustomLogoFile API
583587
func (co *consoleOperator) SyncCustomLogoConfigMap(operatorConfig *operatorv1.Console) (error, string) {
584588
var customLogoRef = operatorv1.ConfigMapFileReference(operatorConfig.Spec.Customization.CustomLogoFile)
585-
return co.UpdateCustomLogoSyncSource(&customLogoRef)
589+
klog.V(4).Infof("[SyncCustomLogoConfigMap] syncing customLogoFile, Name: %s, Key: %s", customLogoRef.Name, customLogoRef.Key)
590+
err, reason := co.ValidateCustomLogo(&customLogoRef)
591+
if err != nil {
592+
klog.V(4).Infof("[SyncCustomLogoConfigMap] failed to sync customLogoFile, %v", err)
593+
return err, reason
594+
}
595+
return co.UpdateCustomLogoSyncSources([]string{customLogoRef.Name})
586596
}
587597

588598
func (co *consoleOperator) ValidateOAuthServingCertConfigMap(ctx context.Context) (oauthServingCert *corev1.ConfigMap, reason string, err error) {
@@ -600,35 +610,54 @@ func (co *consoleOperator) ValidateOAuthServingCertConfigMap(ctx context.Context
600610
}
601611

602612
// on each pass of the operator sync loop, we need to check the
603-
// operator config for a custom logo. If this has been set, then
604-
// we notify the resourceSyncer that it needs to start watching this
605-
// configmap in its own sync loop. Note that the resourceSyncer's actual
613+
// operator config for custom logos. If this has been set, then
614+
// we notify the resourceSyncer that it needs to start watching the associated
615+
// configmaps in its own sync loop. Note that the resourceSyncer's actual
606616
// sync loop will run later. Our operator is waiting to receive
607-
// the copied configmap into the console namespace for a future
617+
// the copied configmaps into the console namespace for a future
608618
// sync loop to mount into the console deployment.
609-
func (c *consoleOperator) UpdateCustomLogoSyncSource(cmRef *operatorv1.ConfigMapFileReference) (error, string) {
610-
// validate first, to avoid a broken volume mount & a crashlooping console
611-
err, reason := c.ValidateCustomLogo(cmRef)
612-
if err != nil {
613-
return err, reason
619+
func (co *consoleOperator) UpdateCustomLogoSyncSources(configMapNames []string) (error, string) {
620+
klog.V(4).Info("[UpdateCustomLogoSyncSources] syncing custom logo configmap resources")
621+
klog.V(4).Infof("%#v", configMapNames)
622+
623+
errors := []string{}
624+
if len(co.trackables.customLogoConfigMaps) > 0 {
625+
klog.V(4).Info("[UpdateCustomLogoSyncSources] unsyncing custom logo configmap resources from previous sync loop...")
626+
for _, configMapName := range co.trackables.customLogoConfigMaps {
627+
err := co.UpdateCustomLogoSyncSource(configMapName, true)
628+
if err != nil {
629+
errors = append(errors, err.Error())
630+
}
631+
}
632+
633+
if len(errors) > 0 {
634+
msg := fmt.Sprintf("error syncing custom logo configmap resources:\n%v", errors)
635+
klog.V(4).Infof("[UpdateCustomLogoSyncSources] %s", msg)
636+
return fmt.Errorf(msg), "FailedResourceSync"
637+
}
614638
}
615639

616-
source := resourcesynccontroller.ResourceLocation{}
617-
logoConfigMapName := cmRef.Name
640+
if len(configMapNames) > 0 {
641+
// If the new list of synced configmaps is different than the last sync, we need to update the
642+
// resource syncer with the new list, and re
643+
klog.V(4).Infof("[UpdateCustomLogoSyncSources] syncing new custom logo configmap resources...")
644+
for _, configMapName := range configMapNames {
645+
err := co.UpdateCustomLogoSyncSource(configMapName, false)
646+
if err != nil {
647+
errors = append(errors, err.Error())
648+
}
649+
}
618650

619-
if logoConfigMapName != "" {
620-
source.Name = logoConfigMapName
621-
source.Namespace = api.OpenShiftConfigNamespace
622-
}
623-
// if no custom logo provided, sync an empty source to delete
624-
err = c.resourceSyncer.SyncConfigMap(
625-
resourcesynccontroller.ResourceLocation{Namespace: api.OpenShiftConsoleNamespace, Name: cmRef.Name},
626-
source,
627-
)
628-
if err != nil {
629-
return err, "FailedResourceSync"
651+
if len(errors) > 0 {
652+
msg := fmt.Sprintf("error syncing custom logo configmap resources:\n%v", errors)
653+
klog.V(4).Infof("[UpdateCustomLogoSyncSources] %s", msg)
654+
return fmt.Errorf(msg), "FailedResourceSync"
655+
}
630656
}
631657

658+
co.trackables.customLogoConfigMaps = configMapNames
659+
660+
klog.V(4).Info("[UpdateCustomLogoSyncSources] done")
632661
return nil, ""
633662
}
634663

@@ -637,34 +666,57 @@ func (co *consoleOperator) ValidateCustomLogo(logoFileRef *operatorv1.ConfigMapF
637666
logoImageKey := logoFileRef.Key
638667

639668
if (len(logoConfigMapName) == 0) != (len(logoImageKey) == 0) {
640-
klog.V(4).Infoln("custom logo filename or key have not been set")
641-
return customerrors.NewCustomLogoError("either custom logo filename or key have not been set"), "KeyOrFilenameInvalid"
669+
msg := "custom logo filename or key have not been set"
670+
klog.V(4).Infof("[ValidateCustomLogo] %s", msg)
671+
return customerrors.NewCustomLogoError(msg), "KeyOrFilenameInvalid"
642672
}
643673
// fine if nothing set, but don't mount it
644674
if len(logoConfigMapName) == 0 {
645-
klog.V(4).Infoln("no custom logo configured")
675+
klog.V(4).Infoln("[ValidateCustomLogo] no custom logo configured")
646676
return nil, ""
647677
}
648678
logoConfigMap, err := co.configNSConfigMapLister.ConfigMaps(api.OpenShiftConfigNamespace).Get(logoConfigMapName)
649679
// If we 404, the logo file may not have been created yet.
650680
if err != nil {
651-
klog.V(4).Infof("failed to get ConfigMap %v, %v", logoConfigMapName, err)
652-
return customerrors.NewCustomLogoError(fmt.Sprintf("failed to get ConfigMap %v, %v", logoConfigMapName, err)), "FailedGet"
681+
msg := fmt.Sprintf("failed to get ConfigMap %v, %v", logoConfigMapName, err)
682+
klog.V(4).Infof("[ValidateCustomLogo] %s", msg)
683+
return customerrors.NewCustomLogoError(msg), "FailedGet"
653684
}
654685

655686
_, imageDataFound := logoConfigMap.BinaryData[logoImageKey]
656687
if !imageDataFound {
657688
_, imageDataFound = logoConfigMap.Data[logoImageKey]
658689
}
659690
if !imageDataFound {
660-
klog.V(4).Infoln("custom logo file exists but no image provided")
661-
return customerrors.NewCustomLogoError("custom logo file exists but no image provided"), "NoImageProvided"
691+
msg := "custom logo file exists but no image provided"
692+
klog.V(4).Infof("[ValidateCustomLogo] %s", msg)
693+
return customerrors.NewCustomLogoError(msg), "NoImageProvided"
662694
}
663695

664-
klog.V(4).Infof("custom logo %s ok to mount", logoConfigMapName)
696+
klog.V(4).Infof("[ValidateCustomLogo] custom logo %s ok to mount", logoConfigMapName)
665697
return nil, ""
666698
}
667699

700+
func (co *consoleOperator) UpdateCustomLogoSyncSource(targetName string, unsync bool) error {
701+
source := resourcesynccontroller.ResourceLocation{}
702+
if !unsync {
703+
source.Name = targetName
704+
source.Namespace = api.OpenShiftConfigNamespace
705+
}
706+
707+
target := resourcesynccontroller.ResourceLocation{
708+
Namespace: api.OpenShiftConsoleNamespace,
709+
Name: targetName,
710+
}
711+
712+
if unsync {
713+
klog.V(4).Infof("[UpdateCustomLogoSyncSource] unsyncing %s", targetName)
714+
} else {
715+
klog.V(4).Infof("[UpdateCustomLogoSyncSource] syncing %s", targetName)
716+
}
717+
return co.resourceSyncer.SyncConfigMap(target, source)
718+
}
719+
668720
func (co *consoleOperator) GetAvailablePlugins(enabledPluginsNames []string) []*v1.ConsolePlugin {
669721
var availablePlugins []*v1.ConsolePlugin
670722
for _, pluginName := range utilsub.RemoveDuplicateStr(enabledPluginsNames) {

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)