diff --git a/hack/test-unit.sh b/hack/test-unit.sh index 30e21199d..56ee14777 100755 --- a/hack/test-unit.sh +++ b/hack/test-unit.sh @@ -10,6 +10,7 @@ PACKAGES_TO_TEST=( "github.com/openshift/console-operator/pkg/console/operator" "github.com/openshift/console-operator/pkg/console/starter" "github.com/openshift/console-operator/pkg/console/subresource/configmap" + "github.com/openshift/console-operator/pkg/console/subresource/consoleserver" "github.com/openshift/console-operator/pkg/console/subresource/deployment" "github.com/openshift/console-operator/pkg/console/subresource/oauthclient" "github.com/openshift/console-operator/pkg/console/subresource/route" diff --git a/pkg/api/api.go b/pkg/api/api.go index da500d4b8..0dd8aeee0 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -15,6 +15,7 @@ const ( OpenShiftConsoleConfigMapName = "console-config" OpenShiftConsolePublicConfigMapName = "console-public" ServiceCAConfigMapName = "service-ca" + DefaultIngressCertConfigMapName = "default-ingress-cert" OpenShiftConsoleDeploymentName = OpenShiftConsoleName OpenShiftConsoleServiceName = OpenShiftConsoleName OpenShiftConsoleRouteName = OpenShiftConsoleName diff --git a/pkg/console/controllers/resourcesyncdestination/controller.go b/pkg/console/controllers/resourcesyncdestination/controller.go new file mode 100644 index 000000000..b6001ca8b --- /dev/null +++ b/pkg/console/controllers/resourcesyncdestination/controller.go @@ -0,0 +1,138 @@ +package resourcesyncdestination + +import ( + "fmt" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/apimachinery/pkg/util/wait" + coreinformersv1 "k8s.io/client-go/informers/core/v1" + coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog" + + operatorsv1 "github.com/openshift/api/operator/v1" + operatorclientv1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1" + operatorinformersv1 "github.com/openshift/client-go/operator/informers/externalversions/operator/v1" + "github.com/openshift/console-operator/pkg/api" + "github.com/openshift/library-go/pkg/operator/events" +) + +const ( + controllerWorkQueueKey = "resource-sync-destination-work-queue-key" + controllerName = "ConsoleResourceSyncDestinationController" +) + +type ResourceSyncDestinationController struct { + operatorConfigClient operatorclientv1.ConsoleInterface + configMapClient coreclientv1.ConfigMapsGetter + // events + cachesToSync []cache.InformerSynced + queue workqueue.RateLimitingInterface + recorder events.Recorder +} + +func NewResourceSyncDestinationController( + // operatorconfig + operatorConfigClient operatorclientv1.ConsoleInterface, + operatorConfigInformer operatorinformersv1.ConsoleInformer, + // configmap + corev1Client coreclientv1.CoreV1Interface, + configMapInformer coreinformersv1.ConfigMapInformer, + // events + recorder events.Recorder, +) *ResourceSyncDestinationController { + corev1Client.ConfigMaps(api.OpenShiftConsoleNamespace) + + ctrl := &ResourceSyncDestinationController{ + operatorConfigClient: operatorConfigClient, + configMapClient: corev1Client, + // events + recorder: recorder, + cachesToSync: nil, + queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), controllerName), + } + + configMapInformer.Informer().AddEventHandler(ctrl.newEventHandler()) + operatorConfigInformer.Informer().AddEventHandler(ctrl.newEventHandler()) + ctrl.cachesToSync = append(ctrl.cachesToSync, + operatorConfigInformer.Informer().HasSynced, + configMapInformer.Informer().HasSynced, + ) + + return ctrl +} + +func (c *ResourceSyncDestinationController) sync() error { + operatorConfig, err := c.operatorConfigClient.Get(api.ConfigResourceName, metav1.GetOptions{}) + if err != nil { + return err + } + + switch operatorConfig.Spec.ManagementState { + case operatorsv1.Managed: + klog.V(4).Infoln("console is in a managed state: syncing default-ingress-cert configmap") + case operatorsv1.Unmanaged: + klog.V(4).Infoln("console is in an unmanaged state: skipping default-ingress-cert configmap sync") + return nil + case operatorsv1.Removed: + klog.V(4).Infoln("console is in an removed state: removing synced default-ingress-cert configmap") + return c.removeDefaultIngressCertConfigMap() + default: + return fmt.Errorf("unknown state: %v", operatorConfig.Spec.ManagementState) + } + + return err +} + +func (c *ResourceSyncDestinationController) removeDefaultIngressCertConfigMap() error { + klog.V(2).Info("deleting default-ingress-cert configmap") + defer klog.V(2).Info("finished deleting default-ingress-cert configmap") + return c.configMapClient.ConfigMaps(api.OpenShiftConsoleNamespace).Delete(api.DefaultIngressCertConfigMapName, &metav1.DeleteOptions{}) +} + +func (c *ResourceSyncDestinationController) Run(workers int, stopCh <-chan struct{}) { + defer runtime.HandleCrash() + defer c.queue.ShutDown() + klog.Infof("starting %v", controllerName) + defer klog.Infof("shutting down %v", controllerName) + if !cache.WaitForCacheSync(stopCh, c.cachesToSync...) { + klog.Infoln("caches did not sync") + runtime.HandleError(fmt.Errorf("caches did not sync")) + return + } + // only start one worker + go wait.Until(c.runWorker, time.Second, stopCh) + <-stopCh +} + +func (c *ResourceSyncDestinationController) runWorker() { + for c.processNextWorkItem() { + } +} + +func (c *ResourceSyncDestinationController) processNextWorkItem() bool { + processKey, quit := c.queue.Get() + if quit { + return false + } + defer c.queue.Done(processKey) + err := c.sync() + if err == nil { + c.queue.Forget(processKey) + return true + } + runtime.HandleError(fmt.Errorf("%v failed with : %v", processKey, err)) + c.queue.AddRateLimited(processKey) + return true +} + +func (c *ResourceSyncDestinationController) newEventHandler() cache.ResourceEventHandler { + return cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { c.queue.Add(controllerWorkQueueKey) }, + UpdateFunc: func(old, new interface{}) { c.queue.Add(controllerWorkQueueKey) }, + DeleteFunc: func(obj interface{}) { c.queue.Add(controllerWorkQueueKey) }, + } +} diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index 6715fd55d..6fd1986f6 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -82,6 +82,12 @@ func (co *consoleOperator) sync_v400(updatedOperatorConfig *operatorv1.Console, // The sync loop may not settle, we are unable to honor it in current state. status.HandleProgressingOrDegraded(updatedOperatorConfig, "CustomLogoSync", customLogoErrReason, customLogoError) + defaultIngressCertConfigMap, defaultIngressCertErrReason, defaultIngressCertErr := co.ValidateDefaultIngressCertConfigMap() + status.HandleProgressingOrDegraded(updatedOperatorConfig, "DefaultIngressCertValidation", defaultIngressCertErrReason, defaultIngressCertErr) + if defaultIngressCertErr != nil { + return defaultIngressCertErr + } + sec, secChanged, secErr := co.SyncSecret(set.Operator) toUpdate = toUpdate || secChanged status.HandleProgressingOrDegraded(updatedOperatorConfig, "OAuthClientSecretSync", "FailedApply", secErr) @@ -96,7 +102,7 @@ func (co *consoleOperator) sync_v400(updatedOperatorConfig *operatorv1.Console, return oauthErr } - actualDeployment, depChanged, depErrReason, depErr := co.SyncDeployment(set.Operator, cm, serviceCAConfigMap, trustedCAConfigMap, sec, rt, set.Proxy, customLogoCanMount) + actualDeployment, depChanged, depErrReason, depErr := co.SyncDeployment(set.Operator, cm, serviceCAConfigMap, defaultIngressCertConfigMap, trustedCAConfigMap, sec, rt, set.Proxy, customLogoCanMount) toUpdate = toUpdate || depChanged status.HandleProgressingOrDegraded(updatedOperatorConfig, "DeploymentSync", depErrReason, depErr) if depErr != nil { @@ -209,13 +215,14 @@ func (co *consoleOperator) SyncDeployment( operatorConfig *operatorv1.Console, cm *corev1.ConfigMap, serviceCAConfigMap *corev1.ConfigMap, + defaultIngressCertConfigMap *corev1.ConfigMap, trustedCAConfigMap *corev1.ConfigMap, sec *corev1.Secret, rt *routev1.Route, proxyConfig *configv1.Proxy, canMountCustomLogo bool) (consoleDeployment *appsv1.Deployment, changed bool, reason string, err error) { - requiredDeployment := deploymentsub.DefaultDeployment(operatorConfig, cm, serviceCAConfigMap, trustedCAConfigMap, sec, rt, proxyConfig, canMountCustomLogo) + requiredDeployment := deploymentsub.DefaultDeployment(operatorConfig, cm, serviceCAConfigMap, defaultIngressCertConfigMap, trustedCAConfigMap, sec, rt, proxyConfig, canMountCustomLogo) expectedGeneration := getDeploymentGeneration(co) genChanged := operatorConfig.ObjectMeta.Generation != operatorConfig.Status.ObservedGeneration @@ -285,7 +292,18 @@ func (co *consoleOperator) SyncConfigMap( return nil, false, "FailedManagedConfig", mcErr } - defaultConfigmap, _, err := configmapsub.DefaultConfigMap(operatorConfig, consoleConfig, managedConfig, infrastructureConfig, consoleRoute) + useDefaultCAFile := true + // We are syncing the `default-ingress-cert` configmap from `openshift-config-managed` to `openshift-console`. + // `default-ingress-cert` is only published in `openshift-config-managed` if an operator-generated default certificate is used. + // It will not exist if all ingresscontrollers user admin-provided default certificates. + // If the `default-ingress-cert` configmap in `openshift-console` exist we should mount that to the console container, + // otherwise default to `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt` + _, rcaErr := co.configMapClient.ConfigMaps(api.OpenShiftConsoleNamespace).Get(api.DefaultIngressCertConfigMapName, metav1.GetOptions{}) + if rcaErr != nil && apierrors.IsNotFound(rcaErr) { + useDefaultCAFile = false + } + + defaultConfigmap, _, err := configmapsub.DefaultConfigMap(operatorConfig, consoleConfig, managedConfig, infrastructureConfig, consoleRoute, useDefaultCAFile) if err != nil { return nil, false, "FailedConsoleConfigBuilder", err } @@ -408,6 +426,20 @@ func (c *consoleOperator) SyncCustomLogoConfigMap(operatorConfig *operatorsv1.Co return okToMount, reason, err } +func (c *consoleOperator) ValidateDefaultIngressCertConfigMap() (defaultIngressCert *corev1.ConfigMap, reason string, err error) { + defaultIngressCertConfigMap, err := c.configMapClient.ConfigMaps(api.OpenShiftConsoleNamespace).Get(api.DefaultIngressCertConfigMapName, metav1.GetOptions{}) + if err != nil { + klog.V(4).Infoln("default-ingress-cert configmap not found") + return nil, "FailedGet", fmt.Errorf("default-ingress-cert configmap not found") + } + + _, caBundle := defaultIngressCertConfigMap.Data["ca-bundle.crt"] + if !caBundle { + return nil, "MissingDefaultIngressCertBundle", fmt.Errorf("default-ingress-cert configmap is missing ca-bundle.crt data") + } + return defaultIngressCertConfigMap, "", nil +} + // on each pass of the operator sync loop, we need to check the // operator config for a custom logo. If this has been set, then // we notify the resourceSyncer that it needs to start watching this diff --git a/pkg/console/starter/starter.go b/pkg/console/starter/starter.go index ee912a85b..2c06b59ab 100644 --- a/pkg/console/starter/starter.go +++ b/pkg/console/starter/starter.go @@ -18,6 +18,7 @@ import ( operatorv1 "github.com/openshift/api/operator" "github.com/openshift/console-operator/pkg/api" "github.com/openshift/console-operator/pkg/console/controllers/clidownloads" + "github.com/openshift/console-operator/pkg/console/controllers/resourcesyncdestination" "github.com/openshift/console-operator/pkg/console/operatorclient" "github.com/openshift/library-go/pkg/controller/controllercmd" "github.com/openshift/library-go/pkg/operator/management" @@ -145,6 +146,11 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { resourceSyncerInformers, resourceSyncer := getResourceSyncer(ctx, clientwrapper.WithoutSecret(kubeClient), operatorClient) + err = startResourceSyncing(resourceSyncer) + if err != nil { + return err + } + consoleMetrics := metrics.Register() // TODO: rearrange these into informer,client pairs, NOT separated. @@ -178,13 +184,13 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { recorder, resourceSyncer, ) + cliDownloadsController := clidownloads.NewCLIDownloadsSyncController( // clients operatorClient, operatorConfigClient.OperatorV1(), consoleClient.ConsoleV1().ConsoleCLIDownloads(), routesClient.RouteV1(), - // informers operatorConfigInformers.Operator().V1().Consoles(), // OperatorConfig consoleInformers.Console().V1().ConsoleCLIDownloads(), // ConsoleCliDownloads @@ -193,6 +199,19 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { recorder, ) + // ResourceSyncDestinationController contains additional logic for all the + // secrets and configmaps that we resourceSyncer is taking care of + resourceSyncDestinationController := resourcesyncdestination.NewResourceSyncDestinationController( + // operatorconfig + operatorConfigClient.OperatorV1().Consoles(), + operatorConfigInformers.Operator().V1().Consoles(), + // configmap + kubeClient.CoreV1(), + kubeInformersNamespaced.Core().V1().ConfigMaps(), + // events + recorder, + ) + consoleServiceController := service.NewServiceSyncController( // clients operatorConfigClient.OperatorV1().Consoles(), // operator config so we can update status @@ -267,6 +286,7 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { } go consoleServiceController.Run(1, ctx.Done()) + go resourceSyncDestinationController.Run(1, ctx.Done()) go consoleOperator.Run(ctx.Done()) go resourceSyncer.Run(1, ctx.Done()) go clusterOperatorStatus.Run(1, ctx.Done()) @@ -280,11 +300,25 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { return fmt.Errorf("stopped") } +// startResourceSyncing should start syncing process of all secrets and configmaps that need to be synced. +func startResourceSyncing(resourceSyncer *resourcesynccontroller.ResourceSyncController) error { + // sync: 'default-ingress-cert' configmap + // from: 'openshift-config-managed' namespace + // to: 'openshift-console' namespace + err := resourceSyncer.SyncConfigMap( + resourcesynccontroller.ResourceLocation{Name: api.DefaultIngressCertConfigMapName, Namespace: api.OpenShiftConsoleNamespace}, + resourcesynccontroller.ResourceLocation{Name: api.DefaultIngressCertConfigMapName, Namespace: api.OpenShiftConfigManagedNamespace}, + ) + + return err +} + func getResourceSyncer(ctx *controllercmd.ControllerContext, kubeClient kubernetes.Interface, operatorClient v1helpers.OperatorClient) (v1helpers.KubeInformersForNamespaces, *resourcesynccontroller.ResourceSyncController) { resourceSyncerInformers := v1helpers.NewKubeInformersForNamespaces( kubeClient, api.OpenShiftConfigNamespace, api.OpenShiftConsoleNamespace, + api.OpenShiftConfigManagedNamespace, ) resourceSyncer := resourcesynccontroller.NewResourceSyncController( operatorClient, diff --git a/pkg/console/subresource/configmap/configmap.go b/pkg/console/subresource/configmap/configmap.go index 2a88e252e..19993eeb3 100644 --- a/pkg/console/subresource/configmap/configmap.go +++ b/pkg/console/subresource/configmap/configmap.go @@ -39,13 +39,15 @@ func DefaultConfigMap( consoleConfig *configv1.Console, managedConfig *corev1.ConfigMap, infrastructureConfig *configv1.Infrastructure, - rt *routev1.Route) (consoleConfigmap *corev1.ConfigMap, unsupportedOverridesHaveMerged bool, err error) { + rt *routev1.Route, + useDefaultCAFile bool) (consoleConfigmap *corev1.ConfigMap, unsupportedOverridesHaveMerged bool, err error) { defaultBuilder := &consoleserver.ConsoleServerCLIConfigBuilder{} defaultConfig, err := defaultBuilder.Host(rt.Spec.Host). LogoutURL(defaultLogoutURL). Brand(DEFAULT_BRAND). DocURL(DEFAULT_DOC_URL). + DefaultIngressCert(useDefaultCAFile). APIServerURL(getApiUrl(infrastructureConfig)). ConfigYAML() @@ -55,6 +57,7 @@ func DefaultConfigMap( LogoutURL(consoleConfig.Spec.Authentication.LogoutRedirect). Brand(operatorConfig.Spec.Customization.Brand). DocURL(operatorConfig.Spec.Customization.DocumentationBaseURL). + DefaultIngressCert(useDefaultCAFile). APIServerURL(getApiUrl(infrastructureConfig)). CustomLogoFile(operatorConfig.Spec.Customization.CustomLogoFile.Key). CustomProductName(operatorConfig.Spec.Customization.CustomProductName). diff --git a/pkg/console/subresource/configmap/configmap_test.go b/pkg/console/subresource/configmap/configmap_test.go index 305a1c2f0..d30c8ee0b 100644 --- a/pkg/console/subresource/configmap/configmap_test.go +++ b/pkg/console/subresource/configmap/configmap_test.go @@ -33,6 +33,7 @@ func TestDefaultConfigMap(t *testing.T) { managedConfig *corev1.ConfigMap infrastructureConfig *configv1.Infrastructure rt *routev1.Route + useDefaultCAFile bool } tests := []struct { name string @@ -55,6 +56,7 @@ func TestDefaultConfigMap(t *testing.T) { Host: host, }, }, + useDefaultCAFile: true, }, want: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -80,6 +82,52 @@ servingInfo: certFile: /var/serving-cert/tls.crt keyFile: /var/serving-cert/tls.key providers: {} +`, + }, + }, + }, + { + name: "Test configmap with default-ingress-cert", + args: args{ + operatorConfig: &operatorv1.Console{}, + consoleConfig: &configv1.Console{}, + managedConfig: &corev1.ConfigMap{}, + infrastructureConfig: &configv1.Infrastructure{ + Status: configv1.InfrastructureStatus{ + APIServerURL: mockAPIServer, + }, + }, + rt: &routev1.Route{ + Spec: routev1.RouteSpec{ + Host: host, + }, + }, + useDefaultCAFile: false, + }, + want: &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: api.OpenShiftConsoleConfigMapName, + Namespace: api.OpenShiftConsoleNamespace, + Labels: map[string]string{"app": api.OpenShiftConsoleName}, + Annotations: map[string]string{}, + }, + Data: map[string]string{configKey: `kind: ConsoleConfig +apiVersion: console.openshift.io/v1 +auth: + clientID: console + clientSecretFile: /var/oauth-config/clientSecret + oauthEndpointCAFile: /var/default-ingress-cert/ca-bundle.crt +clusterInfo: + consoleBaseAddress: https://` + host + ` + masterPublicURL: ` + mockAPIServer + ` +customization: + branding: ` + DEFAULT_BRAND + ` + documentationBaseURL: ` + DEFAULT_DOC_URL + ` +servingInfo: + bindAddress: https://0.0.0.0:8443 + certFile: /var/serving-cert/tls.crt + keyFile: /var/serving-cert/tls.key +providers: {} `, }, }, @@ -108,6 +156,7 @@ customization: Host: host, }, }, + useDefaultCAFile: true, }, want: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -170,6 +219,7 @@ customization: Host: host, }, }, + useDefaultCAFile: true, }, want: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -237,6 +287,7 @@ customization: Host: host, }, }, + useDefaultCAFile: true, }, want: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -306,6 +357,7 @@ customization: Host: host, }, }, + useDefaultCAFile: true, }, want: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -339,7 +391,7 @@ providers: } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cm, _, _ := DefaultConfigMap(tt.args.operatorConfig, tt.args.consoleConfig, tt.args.managedConfig, tt.args.infrastructureConfig, tt.args.rt) + cm, _, _ := DefaultConfigMap(tt.args.operatorConfig, tt.args.consoleConfig, tt.args.managedConfig, tt.args.infrastructureConfig, tt.args.rt, tt.args.useDefaultCAFile) // marshall the exampleYaml to map[string]interface{} so we can use it in diff below var exampleConfig map[string]interface{} diff --git a/pkg/console/subresource/consoleserver/config_builder.go b/pkg/console/subresource/consoleserver/config_builder.go index 3e5b93148..1a9ae8480 100644 --- a/pkg/console/subresource/consoleserver/config_builder.go +++ b/pkg/console/subresource/consoleserver/config_builder.go @@ -9,8 +9,9 @@ import ( ) const ( - clientSecretFilePath = "/var/oauth-config/clientSecret" - oauthEndpointCAFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + clientSecretFilePath = "/var/oauth-config/clientSecret" + defaultIngressCertFilePath = "/var/default-ingress-cert/ca-bundle.crt" + oauthEndpointCAFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" // serving info certFilePath = "/var/serving-cert/tls.crt" keyFilePath = "/var/serving-cert/tls.key" @@ -36,6 +37,7 @@ type ConsoleServerCLIConfigBuilder struct { statusPageID string customProductName string customLogoFile string + CAFile string } func (b *ConsoleServerCLIConfigBuilder) Host(host string) *ConsoleServerCLIConfigBuilder { @@ -74,6 +76,15 @@ func (b *ConsoleServerCLIConfigBuilder) StatusPageID(id string) *ConsoleServerCL return b } +func (b *ConsoleServerCLIConfigBuilder) DefaultIngressCert(useDefaultDefaultIngressCert bool) *ConsoleServerCLIConfigBuilder { + if useDefaultDefaultIngressCert { + b.CAFile = oauthEndpointCAFilePath + return b + } + b.CAFile = defaultIngressCertFilePath + return b +} + func (b *ConsoleServerCLIConfigBuilder) Config() Config { return Config{ Kind: "ConsoleConfig", @@ -119,10 +130,15 @@ func (b *ConsoleServerCLIConfigBuilder) clusterInfo() ClusterInfo { } func (b *ConsoleServerCLIConfigBuilder) authServer() Auth { + // we need this fallback due to the way our unit test are structured, + // where the ConsoleServerCLIConfigBuilder object is being instantiated empty + if b.CAFile == "" { + b.CAFile = oauthEndpointCAFilePath + } conf := Auth{ ClientID: api.OpenShiftConsoleName, ClientSecretFile: clientSecretFilePath, - OAuthEndpointCAFile: oauthEndpointCAFilePath, + OAuthEndpointCAFile: b.CAFile, } if len(b.logoutRedirectURL) > 0 { conf.LogoutRedirect = b.logoutRedirectURL diff --git a/pkg/console/subresource/consoleserver/config_builder_test.go b/pkg/console/subresource/consoleserver/config_builder_test.go index 2628ee4da..12214d150 100644 --- a/pkg/console/subresource/consoleserver/config_builder_test.go +++ b/pkg/console/subresource/consoleserver/config_builder_test.go @@ -51,6 +51,7 @@ func TestConsoleServerCLIConfigBuilder(t *testing.T) { APIServerURL("https://foobar.com/api"). Host("https://foobar.com/host"). LogoutURL("https://foobar.com/logout"). + DefaultIngressCert(false). Config() }, output: Config{ @@ -69,7 +70,7 @@ func TestConsoleServerCLIConfigBuilder(t *testing.T) { Auth: Auth{ ClientID: api.OpenShiftConsoleName, ClientSecretFile: clientSecretFilePath, - OAuthEndpointCAFile: oauthEndpointCAFilePath, + OAuthEndpointCAFile: defaultIngressCertFilePath, LogoutRedirect: "https://foobar.com/logout", }, Customization: Customization{}, @@ -192,6 +193,7 @@ providers: {} APIServerURL("https://foobar.com/api"). Host("https://foobar.com/host"). LogoutURL("https://foobar.com/logout"). + DefaultIngressCert(false). ConfigYAML() }, output: `apiVersion: console.openshift.io/v1 @@ -206,7 +208,7 @@ clusterInfo: auth: clientID: console clientSecretFile: /var/oauth-config/clientSecret - oauthEndpointCAFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt + oauthEndpointCAFile: /var/default-ingress-cert/ca-bundle.crt logoutRedirect: https://foobar.com/logout customization: {} providers: {} @@ -243,7 +245,8 @@ providers: Brand(v1.BrandOKD). DocURL("https://foobar.com/docs"). APIServerURL("https://foobar.com/api"). - StatusPageID("status-12345") + StatusPageID("status-12345"). + DefaultIngressCert(true) return b.ConfigYAML() }, output: `apiVersion: console.openshift.io/v1 diff --git a/pkg/console/subresource/deployment/deployment.go b/pkg/console/subresource/deployment/deployment.go index 9a179abf9..9b67f9c9e 100644 --- a/pkg/console/subresource/deployment/deployment.go +++ b/pkg/console/subresource/deployment/deployment.go @@ -31,12 +31,13 @@ const ( ) const ( - configMapResourceVersionAnnotation = "console.openshift.io/console-config-version" - proxyConfigResourceVersionAnnotation = "console.openshift.io/proxy-config-version" - serviceCAConfigMapResourceVersionAnnotation = "console.openshift.io/service-ca-config-version" - trustedCAConfigMapResourceVersionAnnotation = "console.openshift.io/trusted-ca-config-version" - secretResourceVersionAnnotation = "console.openshift.io/oauth-secret-version" - consoleImageAnnotation = "console.openshift.io/image" + configMapResourceVersionAnnotation = "console.openshift.io/console-config-version" + proxyConfigResourceVersionAnnotation = "console.openshift.io/proxy-config-version" + serviceCAConfigMapResourceVersionAnnotation = "console.openshift.io/service-ca-config-version" + defaultIngressCertConfigMapResourceVersionAnnotation = "console.openshift.io/default-ingress-cert-config-version" + trustedCAConfigMapResourceVersionAnnotation = "console.openshift.io/trusted-ca-config-version" + secretResourceVersionAnnotation = "console.openshift.io/oauth-secret-version" + consoleImageAnnotation = "console.openshift.io/image" ) var ( @@ -44,6 +45,7 @@ var ( configMapResourceVersionAnnotation, proxyConfigResourceVersionAnnotation, serviceCAConfigMapResourceVersionAnnotation, + defaultIngressCertConfigMapResourceVersionAnnotation, trustedCAConfigMapResourceVersionAnnotation, secretResourceVersionAnnotation, consoleImageAnnotation, @@ -61,17 +63,18 @@ type volumeConfig struct { mappedKeys map[string]string } -func DefaultDeployment(operatorConfig *operatorv1.Console, cm *corev1.ConfigMap, serviceCAConfigMap *corev1.ConfigMap, trustedCAConfigMap *corev1.ConfigMap, sec *corev1.Secret, rt *routev1.Route, proxyConfig *configv1.Proxy, canMountCustomLogo bool) *appsv1.Deployment { +func DefaultDeployment(operatorConfig *operatorv1.Console, cm *corev1.ConfigMap, serviceCAConfigMap *corev1.ConfigMap, defaultIngressCertConfigMap *corev1.ConfigMap, trustedCAConfigMap *corev1.ConfigMap, sec *corev1.Secret, rt *routev1.Route, proxyConfig *configv1.Proxy, canMountCustomLogo bool) *appsv1.Deployment { labels := util.LabelsForConsole() meta := util.SharedMeta() meta.Labels = labels annotations := map[string]string{ - configMapResourceVersionAnnotation: cm.GetResourceVersion(), - serviceCAConfigMapResourceVersionAnnotation: serviceCAConfigMap.GetResourceVersion(), - trustedCAConfigMapResourceVersionAnnotation: trustedCAConfigMap.GetResourceVersion(), - proxyConfigResourceVersionAnnotation: proxyConfig.GetResourceVersion(), - secretResourceVersionAnnotation: sec.GetResourceVersion(), - consoleImageAnnotation: util.GetImageEnv(), + configMapResourceVersionAnnotation: cm.GetResourceVersion(), + serviceCAConfigMapResourceVersionAnnotation: serviceCAConfigMap.GetResourceVersion(), + defaultIngressCertConfigMapResourceVersionAnnotation: defaultIngressCertConfigMap.GetResourceVersion(), + trustedCAConfigMapResourceVersionAnnotation: trustedCAConfigMap.GetResourceVersion(), + proxyConfigResourceVersionAnnotation: proxyConfig.GetResourceVersion(), + secretResourceVersionAnnotation: sec.GetResourceVersion(), + consoleImageAnnotation: util.GetImageEnv(), } // Set any annotations as needed so that `ApplyDeployment` rolls out a // new version when they change. `ApplyDeployment` doesn't compare that @@ -419,6 +422,12 @@ func defaultVolumeConfig() []volumeConfig { path: "/var/service-ca", isConfigMap: true, }, + { + name: api.DefaultIngressCertConfigMapName, + readOnly: true, + path: "/var/default-ingress-cert", + isConfigMap: true, + }, } } diff --git a/pkg/console/subresource/deployment/deployment_test.go b/pkg/console/subresource/deployment/deployment_test.go index a68162f64..7d0b1e411 100644 --- a/pkg/console/subresource/deployment/deployment_test.go +++ b/pkg/console/subresource/deployment/deployment_test.go @@ -27,6 +27,7 @@ func TestDefaultDeployment(t *testing.T) { config *operatorsv1.Console cm *corev1.ConfigMap ca *corev1.ConfigMap + dica *corev1.ConfigMap tca *corev1.ConfigMap sec *corev1.Secret rt *v1.Route @@ -58,12 +59,13 @@ func TestDefaultDeployment(t *testing.T) { DeletionGracePeriodSeconds: nil, Labels: labels, Annotations: map[string]string{ - configMapResourceVersionAnnotation: "", - secretResourceVersionAnnotation: "", - serviceCAConfigMapResourceVersionAnnotation: "", - trustedCAConfigMapResourceVersionAnnotation: "", - proxyConfigResourceVersionAnnotation: "", - consoleImageAnnotation: "", + configMapResourceVersionAnnotation: "", + secretResourceVersionAnnotation: "", + defaultIngressCertConfigMapResourceVersionAnnotation: "", + serviceCAConfigMapResourceVersionAnnotation: "", + trustedCAConfigMapResourceVersionAnnotation: "", + proxyConfigResourceVersionAnnotation: "", + consoleImageAnnotation: "", }, OwnerReferences: nil, Finalizers: nil, @@ -114,12 +116,13 @@ func TestDefaultDeployment(t *testing.T) { } consoleDeploymentTemplateAnnotations := map[string]string{ - configMapResourceVersionAnnotation: "", - secretResourceVersionAnnotation: "", - serviceCAConfigMapResourceVersionAnnotation: "", - trustedCAConfigMapResourceVersionAnnotation: "", - proxyConfigResourceVersionAnnotation: "", - consoleImageAnnotation: "", + configMapResourceVersionAnnotation: "", + secretResourceVersionAnnotation: "", + defaultIngressCertConfigMapResourceVersionAnnotation: "", + serviceCAConfigMapResourceVersionAnnotation: "", + trustedCAConfigMapResourceVersionAnnotation: "", + proxyConfigResourceVersionAnnotation: "", + consoleImageAnnotation: "", } consoleDeploymentAffinity := &corev1.Affinity{ @@ -162,7 +165,10 @@ func TestDefaultDeployment(t *testing.T) { config: consoleOperatorConfig, cm: consoleConfig, ca: &corev1.ConfigMap{}, - tca: trustedCAConfigMapEmpty, + dica: &corev1.ConfigMap{ + Data: map[string]string{"ca-bundle.crt": "test"}, + }, + tca: trustedCAConfigMapEmpty, sec: &corev1.Secret{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{}, @@ -224,7 +230,10 @@ func TestDefaultDeployment(t *testing.T) { config: consoleOperatorConfig, cm: consoleConfig, ca: &corev1.ConfigMap{}, - tca: trustedCAConfigMapSet, + dica: &corev1.ConfigMap{ + Data: map[string]string{"ca-bundle.crt": "test"}, + }, + tca: trustedCAConfigMapSet, sec: &corev1.Secret{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{}, @@ -283,7 +292,7 @@ func TestDefaultDeployment(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if diff := deep.Equal(DefaultDeployment(tt.args.config, tt.args.cm, tt.args.cm, tt.args.tca, tt.args.sec, tt.args.rt, tt.args.proxy, tt.args.canMountCustomLogo), tt.want); diff != nil { + if diff := deep.Equal(DefaultDeployment(tt.args.config, tt.args.cm, tt.args.dica, tt.args.cm, tt.args.tca, tt.args.sec, tt.args.rt, tt.args.proxy, tt.args.canMountCustomLogo), tt.want); diff != nil { t.Error(diff) } }) @@ -387,6 +396,19 @@ func Test_consoleVolumes(t *testing.T) { }, }, } + defaultIngressCert := corev1.Volume{ + Name: api.DefaultIngressCertConfigMapName, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: api.DefaultIngressCertConfigMapName, + }, + Items: nil, + DefaultMode: nil, + Optional: nil, + }, + }, + } tests := []struct { name string args args @@ -402,6 +424,7 @@ func Test_consoleVolumes(t *testing.T) { consoleOauthConfig, consoleConfig, serviceCA, + defaultIngressCert, }, }, { @@ -414,6 +437,7 @@ func Test_consoleVolumes(t *testing.T) { consoleOauthConfig, consoleConfig, serviceCA, + defaultIngressCert, { Name: api.TrustedCAConfigMapName, VolumeSource: corev1.VolumeSource{ @@ -479,6 +503,11 @@ func Test_consoleVolumeMounts(t *testing.T) { ReadOnly: true, MountPath: "/var/service-ca", }, + { + Name: api.DefaultIngressCertConfigMapName, + ReadOnly: true, + MountPath: "/var/default-ingress-cert", + }, }, }, {name: "Test console volumes Mounts with TrustedCA", @@ -506,6 +535,11 @@ func Test_consoleVolumeMounts(t *testing.T) { ReadOnly: true, MountPath: "/var/service-ca", }, + { + Name: api.DefaultIngressCertConfigMapName, + ReadOnly: true, + MountPath: "/var/default-ingress-cert", + }, { Name: api.TrustedCAConfigMapName, ReadOnly: true,