From ae380773a7ac28bb1fff3b06684125696ae092e3 Mon Sep 17 00:00:00 2001 From: zherman0 Date: Fri, 29 Mar 2019 10:15:32 -0600 Subject: [PATCH] Make normal dockerfile default to ocp --- Dockerfile | 8 +- ...rbac-role-ns-openshift-config-managed.yaml | 14 ++ manifests/04-rbac-rolebinding.yaml | 14 ++ pkg/api/api.go | 1 + pkg/console/operator/operator.go | 3 + pkg/console/operator/sync_v400.go | 15 +- pkg/console/starter/starter.go | 27 ++- .../subresource/configmap/configmap.go | 20 ++- .../subresource/configmap/configmap_test.go | 161 ++++++++++++++---- 9 files changed, 209 insertions(+), 54 deletions(-) create mode 100644 manifests/03-rbac-role-ns-openshift-config-managed.yaml diff --git a/Dockerfile b/Dockerfile index c1b7357321..48999b775f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,7 @@ FROM registry.svc.ci.openshift.org/openshift/release:golang-1.10 AS builder -# create a work dir and copy local files in WORKDIR /go/src/github.com/openshift/console-operator COPY . . -RUN make build +RUN ADDITIONAL_GOTAGS="ocp" make build WHAT="cmd/console" FROM registry.svc.ci.openshift.org/openshift/origin-v4.0:base RUN useradd console-operator @@ -19,8 +18,3 @@ LABEL io.k8s.display-name="OpenShift console-operator" \ LABEL io.openshift.release.operator true -# entrypoint specified in 03-operator.yaml as `console-operator` -# CMD ["/usr/bin/console", "operator", "--kubeconfig", "path/to/config", "--config", "./install/config.yaml", "--v", "4"] -# CMD ["/usr/bin/console", "operator", "--v", "4"] - - diff --git a/manifests/03-rbac-role-ns-openshift-config-managed.yaml b/manifests/03-rbac-role-ns-openshift-config-managed.yaml new file mode 100644 index 0000000000..dede0a46c2 --- /dev/null +++ b/manifests/03-rbac-role-ns-openshift-config-managed.yaml @@ -0,0 +1,14 @@ +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: console-operator + namespace: openshift-config-managed +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch diff --git a/manifests/04-rbac-rolebinding.yaml b/manifests/04-rbac-rolebinding.yaml index 16e94572b7..b99ef625f5 100644 --- a/manifests/04-rbac-rolebinding.yaml +++ b/manifests/04-rbac-rolebinding.yaml @@ -37,3 +37,17 @@ subjects: - kind: ServiceAccount name: console-operator namespace: openshift-console-operator +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: console-operator + namespace: openshift-config-managed +roleRef: + kind: Role + name: console-operator + apiGroup: rbac.authorization.k8s.io +subjects: + - kind: ServiceAccount + name: console-operator + namespace: openshift-console-operator diff --git a/pkg/api/api.go b/pkg/api/api.go index 6aac47565c..8bfde53a52 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -16,4 +16,5 @@ const ( OpenShiftConsoleServiceName = OpenShiftConsoleName OpenShiftConsoleRouteName = OpenShiftConsoleName OAuthClientName = OpenShiftConsoleName + OpenshiftConfigManagedNamespace = "openshift-config-managed" ) diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index fba0a889ff..5457ba2c04 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -77,6 +77,7 @@ func NewConsoleOperator( configInformer configinformer.SharedInformerFactory, coreV1 corev1.Interface, + managedCoreV1 corev1.Interface, deployments appsinformersv1.DeploymentInformer, routes routesinformersv1.RouteInformer, oauthClients oauthinformersv1.OAuthClientInformer, @@ -113,6 +114,7 @@ func NewConsoleOperator( secretsInformer := coreV1.Secrets() configMapInformer := coreV1.ConfigMaps() + managedConfigMapInformer := managedCoreV1.ConfigMaps() serviceInformer := coreV1.Services() configV1Informers := configInformer.Config().V1() @@ -131,6 +133,7 @@ func NewConsoleOperator( operator.WithInformer(oauthClients, targetNameFilter), // special resources with unique names operator.WithInformer(configMapInformer, operator.FilterByNames(configmap.ConsoleConfigMapName, configmap.ServiceCAConfigMapName)), + operator.WithInformer(managedConfigMapInformer, operator.FilterByNames(configmap.ConsoleConfigMapName)), operator.WithInformer(secretsInformer, operator.FilterByNames(deployment.ConsoleOauthConfigName)), ) } diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index eb1163ff51..30f22da5eb 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -7,10 +7,6 @@ import ( "reflect" "strings" - "github.com/openshift/console-operator/pkg/console/subresource/util" - - "github.com/openshift/console-operator/pkg/api" - // 3rd party "github.com/sirupsen/logrus" // kube @@ -24,6 +20,8 @@ import ( // openshift configv1 "github.com/openshift/api/config/v1" operatorv1 "github.com/openshift/api/operator/v1" + "github.com/openshift/console-operator/pkg/api" + "github.com/openshift/console-operator/pkg/console/subresource/util" "github.com/openshift/console-operator/pkg/crypto" "github.com/openshift/library-go/pkg/operator/events" "github.com/openshift/library-go/pkg/operator/resource/resourceapply" @@ -249,11 +247,16 @@ func SyncSecret(co *consoleOperator, recorder events.Recorder, operatorConfig *o func SyncConfigMap(co *consoleOperator, recorder events.Recorder, operatorConfig *operatorv1.Console, consoleConfig *configv1.Console, infrastructureConfig *configv1.Infrastructure, rt *routev1.Route) (*corev1.ConfigMap, bool, error) { logrus.Printf("validating console configmap...") - defaultConfigmap, _, err := configmapsub.DefaultConfigMap(operatorConfig, consoleConfig, infrastructureConfig, rt) + managedConfig, mcErr := co.configMapClient.ConfigMaps(api.OpenshiftConfigManagedNamespace).Get(api.OpenShiftConsoleConfigMapName, metav1.GetOptions{}) + if mcErr != nil && !apierrors.IsNotFound(mcErr) { + logrus.Errorf("managed config error: %v \n", mcErr) + return nil, false, mcErr + } + + defaultConfigmap, _, err := configmapsub.DefaultConfigMap(operatorConfig, consoleConfig, managedConfig, infrastructureConfig, rt) if err != nil { return nil, false, err } - cm, cmChanged, cmErr := resourceapply.ApplyConfigMap(co.configMapClient, recorder, defaultConfigmap) if cmErr != nil { logrus.Errorf("%q: %v \n", "configmap", cmErr) diff --git a/pkg/console/starter/starter.go b/pkg/console/starter/starter.go index c6dc62ecf9..44c6e02d80 100644 --- a/pkg/console/starter/starter.go +++ b/pkg/console/starter/starter.go @@ -83,6 +83,11 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { informers.WithNamespace(api.TargetNamespace), ) + kubeInformersManagedNamespaced := informers.NewSharedInformerFactoryWithOptions( + kubeClient, + resync, + informers.WithNamespace(api.OpenshiftConfigManagedNamespace), + ) // configs are all named "cluster", but our clusteroperator is named "console" configInformers := configinformers.NewSharedInformerFactoryWithOptions( configClient, @@ -108,13 +113,13 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { oauthinformers.WithTweakListOptions(tweakListOptionsForOAuth), ) - recorder := ctx.EventRecorder - operatorClient := &operatorclient.OperatorClient{ Informers: operatorConfigInformers, Client: operatorConfigClient.OperatorV1(), } + recorder := ctx.EventRecorder + versionGetter := status.NewVersionGetter() // TODO: rearrange these into informer,client pairs, NOT separated. @@ -123,6 +128,7 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { operatorConfigInformers.Operator().V1().Consoles(), // OperatorConfig configInformers, // ConsoleConfig kubeInformersNamespaced.Core().V1(), // Secrets, ConfigMaps, Service + kubeInformersManagedNamespaced.Core().V1(), // Managed ConfigMaps kubeInformersNamespaced.Apps().V1().Deployments(), // Deployments routesInformersNamespaced.Route().V1().Routes(), // Route oauthInformers.Oauth().V1().OAuthClients(), // OAuth clients @@ -163,11 +169,18 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { configUpgradeableController := unsupportedconfigoverridescontroller.NewUnsupportedConfigOverridesController(operatorClient, ctx.EventRecorder) - kubeInformersNamespaced.Start(ctx.Done()) - operatorConfigInformers.Start(ctx.Done()) - configInformers.Start(ctx.Done()) - routesInformersNamespaced.Start(ctx.Done()) - oauthInformers.Start(ctx.Done()) + for _, informer := range []interface { + Start(stopCh <-chan struct{}) + }{ + kubeInformersNamespaced, + kubeInformersManagedNamespaced, + operatorConfigInformers, + configInformers, + routesInformersNamespaced, + oauthInformers, + } { + informer.Start(ctx.Done()) + } go consoleOperator.Run(ctx.Done()) go clusterOperatorStatus.Run(1, ctx.Done()) diff --git a/pkg/console/subresource/configmap/configmap.go b/pkg/console/subresource/configmap/configmap.go index 105bb1b5f0..3332447372 100644 --- a/pkg/console/subresource/configmap/configmap.go +++ b/pkg/console/subresource/configmap/configmap.go @@ -2,11 +2,10 @@ package configmap import ( "fmt" - "github.com/sirupsen/logrus" yaml2 "github.com/ghodss/yaml" - yaml "gopkg.in/yaml.v2" + "gopkg.in/yaml.v2" corev1 "k8s.io/api/core/v1" @@ -65,7 +64,7 @@ func getApiUrl(infrastructureConfig *configv1.Infrastructure) string { // - a new configmap, // - a bool indicating if config was merged (unsupportedConfigOverrides) // - an error -func DefaultConfigMap(operatorConfig *operatorv1.Console, consoleConfig *configv1.Console, infrastructureConfig *configv1.Infrastructure, rt *routev1.Route) (*corev1.ConfigMap, bool, error) { +func DefaultConfigMap(operatorConfig *operatorv1.Console, consoleConfig *configv1.Console, managedConfig *corev1.ConfigMap, infrastructureConfig *configv1.Infrastructure, rt *routev1.Route) (*corev1.ConfigMap, bool, error) { logoutRedirect := getLogoutRedirect(consoleConfig) brand := getBrand(operatorConfig) docURL := getDocURL(operatorConfig) @@ -77,11 +76,12 @@ func DefaultConfigMap(operatorConfig *operatorv1.Console, consoleConfig *configv configMap := Stub() configMap.Data = map[string]string{} unsupportedRaw := operatorConfig.Spec.UnsupportedConfigOverrides.Raw + newConfig := extractYAML(managedConfig) // merge config overrides, if we have them - mergedConfig, err := resourcemerge.MergeProcessConfig(nil, config, unsupportedRaw) + mergedConfig, err := resourcemerge.MergeProcessConfig(nil, config, newConfig, unsupportedRaw) if err != nil { - logrus.Errorf("failed to generate configmap: %v \n", err) + logrus.Errorf("failed to merge configmap: %v \n", err) return nil, false, err } @@ -193,3 +193,13 @@ func authServerYaml(logoutRedirect string) yaml.MapSlice { func consoleBaseAddr(host string) string { return util.HTTPS(host) } + +// Helper function that pulls the yaml struct out of the data section of a configmap yaml +func extractYAML(managedConfig *corev1.ConfigMap) []byte { + data := managedConfig.Data + for _, v := range data { + return []byte(v) + } + + return []byte{} +} diff --git a/pkg/console/subresource/configmap/configmap_test.go b/pkg/console/subresource/configmap/configmap_test.go index dd0c42ef34..f329b4d21a 100644 --- a/pkg/console/subresource/configmap/configmap_test.go +++ b/pkg/console/subresource/configmap/configmap_test.go @@ -39,6 +39,31 @@ servingInfo: bindAddress: https://0.0.0.0:8443 certFile: /var/serving-cert/tls.crt keyFile: /var/serving-cert/tls.key +` + exampleManagedConfigMapData = `kind: ConsoleConfig +apiVersion: console.openshift.io/v1beta1 +customization: + branding: online + documentationBaseURL: https://docs.okd.io/4.0/ +` + exampleYamlWithManagedConfig = `kind: ConsoleConfig +apiVersion: console.openshift.io/v1beta1 +auth: + clientID: console + clientSecretFile: /var/oauth-config/clientSecret + logoutRedirect: "" + oauthEndpointCAFile: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt +clusterInfo: + consoleBaseAddress: https://` + host + ` + consoleBasePath: "" + masterPublicURL: ` + mockAPIServer + ` +customization: + branding: online + documentationBaseURL: https://docs.okd.io/4.0/ +servingInfo: + bindAddress: https://0.0.0.0:8443 + certFile: /var/serving-cert/tls.crt + keyFile: /var/serving-cert/tls.key ` ) @@ -47,6 +72,7 @@ func TestDefaultConfigMap(t *testing.T) { type args struct { operatorConfig *operatorv1.Console consoleConfig *configv1.Console + managedConfig *corev1.ConfigMap infrastructureConfig *configv1.Infrastructure rt *routev1.Route } @@ -56,7 +82,7 @@ func TestDefaultConfigMap(t *testing.T) { want *corev1.ConfigMap }{ { - name: "Test Default Config Map", + name: "Test generating default configmap without managed config override", args: args{ operatorConfig: &operatorv1.Console{ TypeMeta: metav1.TypeMeta{}, @@ -68,6 +94,7 @@ func TestDefaultConfigMap(t *testing.T) { Spec: configv1.ConsoleSpec{}, Status: configv1.ConsoleStatus{}, }, + managedConfig: &corev1.ConfigMap{}, infrastructureConfig: &configv1.Infrastructure{ Status: configv1.InfrastructureStatus{ APIServerURL: mockAPIServer, @@ -77,13 +104,7 @@ func TestDefaultConfigMap(t *testing.T) { TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{}, Spec: routev1.RouteSpec{ - Host: host, - Path: "", - To: routev1.RouteTargetReference{}, - AlternateBackends: nil, - Port: nil, - TLS: nil, - WildcardPolicy: "", + Host: host, }, Status: routev1.RouteStatus{}, }, @@ -91,40 +112,77 @@ func TestDefaultConfigMap(t *testing.T) { want: &corev1.ConfigMap{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ - Name: ConsoleConfigMapName, - GenerateName: "", - Namespace: api.OpenShiftConsoleNamespace, - SelfLink: "", - UID: "", - ResourceVersion: "", - Generation: 0, - CreationTimestamp: metav1.Time{}, - DeletionTimestamp: nil, - DeletionGracePeriodSeconds: nil, - Labels: map[string]string{"app": api.OpenShiftConsoleName}, - Annotations: map[string]string{}, - OwnerReferences: nil, - Initializers: nil, - Finalizers: nil, - ClusterName: "", + Name: ConsoleConfigMapName, + Namespace: api.OpenShiftConsoleNamespace, + Labels: map[string]string{"app": api.OpenShiftConsoleName}, + Annotations: map[string]string{}, }, - Data: map[string]string{configKey: exampleYaml}, - BinaryData: nil, + Data: map[string]string{configKey: exampleYaml}, + }, + }, + { + name: "Test generating configmap with managed config to override branding", + args: args{ + operatorConfig: &operatorv1.Console{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: operatorv1.ConsoleSpec{}, + Status: operatorv1.ConsoleStatus{}, + }, + consoleConfig: &configv1.Console{ + Spec: configv1.ConsoleSpec{}, + Status: configv1.ConsoleStatus{}, + }, + managedConfig: &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "console-config", + Namespace: "openshift-config-managed", + }, + Data: map[string]string{configKey: exampleManagedConfigMapData}, + BinaryData: nil, + }, + infrastructureConfig: &configv1.Infrastructure{ + Status: configv1.InfrastructureStatus{ + APIServerURL: mockAPIServer, + }, + }, + rt: &routev1.Route{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{}, + Spec: routev1.RouteSpec{ + Host: host, + }, + Status: routev1.RouteStatus{}, + }, + }, + want: &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: ConsoleConfigMapName, + Namespace: api.OpenShiftConsoleNamespace, + Labels: map[string]string{"app": api.OpenShiftConsoleName}, + Annotations: map[string]string{}, + }, + Data: map[string]string{configKey: exampleYamlWithManagedConfig}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - cm, _, _ := DefaultConfigMap(tt.args.operatorConfig, tt.args.consoleConfig, tt.args.infrastructureConfig, tt.args.rt) + cm, _, _ := DefaultConfigMap(tt.args.operatorConfig, tt.args.consoleConfig, tt.args.managedConfig, tt.args.infrastructureConfig, tt.args.rt) // marshall the exampleYaml to map[string]interface{} so we can use it in diff below var exampleConfig map[string]interface{} - exampleBytes := []byte(exampleYaml) + exampleBytes := []byte(tt.want.Data[configKey]) err := yaml.Unmarshal(exampleBytes, &exampleConfig) if err != nil { t.Error(err) + fmt.Printf("%v\n", exampleConfig) } - fmt.Printf("%v\n", exampleConfig) // the reason we have to marshall blindly into map[string]interface{} // is that we don't have the definition for the console config struct. @@ -259,3 +317,48 @@ func Test_consoleBaseAddr(t *testing.T) { }) } } + +func Test_extractYAML(t *testing.T) { + type args struct { + newConfig *corev1.ConfigMap + } + tests := []struct { + name string + args args + want string + }{ + { + name: "Test getting data from configmap as yaml", + args: args{ + newConfig: &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "console-config", + Namespace: "openshift-config-managed", + }, + Data: map[string]string{configKey: exampleManagedConfigMapData}, + BinaryData: nil, + }, + }, + want: `kind: ConsoleConfig +apiVersion: console.openshift.io/v1beta1 +customization: + branding: online + documentationBaseURL: https://docs.okd.io/4.0/ +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractYAML(tt.args.newConfig) + if diff := deep.Equal(result, []byte(tt.want)); diff != nil { + t.Error(diff) + t.Errorf("Got: %v \n", result) + t.Errorf("Want: %v \n", []byte(tt.want)) + } + }) + } +}