diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 12e0dd83..8e6b44b9 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -96,7 +96,6 @@ jobs: - resource-retain-duration - resource-retain-on-failure - resource-selector - - watched-namespaces - driver-start-timeout exclude: - mode: dynamic @@ -113,8 +112,6 @@ jobs: test-group: resource-selector - mode: dynamic test-group: driver-start-timeout - - mode: static - test-group: watched-namespaces - mode: static test-group: resource-selector - mode: selector @@ -127,8 +124,6 @@ jobs: test-group: resource-retain-duration - mode: selector test-group: resource-retain-on-failure - - mode: selector - test-group: watched-namespaces - mode: selector test-group: driver-start-timeout include: diff --git a/spark-operator/src/main/java/org/apache/spark/k8s/operator/SparkOperator.java b/spark-operator/src/main/java/org/apache/spark/k8s/operator/SparkOperator.java index 2f8f98f6..82f271f0 100644 --- a/spark-operator/src/main/java/org/apache/spark/k8s/operator/SparkOperator.java +++ b/spark-operator/src/main/java/org/apache/spark/k8s/operator/SparkOperator.java @@ -26,7 +26,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -37,7 +36,6 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.http.Interceptor; import io.javaoperatorsdk.operator.Operator; -import io.javaoperatorsdk.operator.RegisteredController; import io.javaoperatorsdk.operator.api.config.ConfigurationServiceOverrider; import io.javaoperatorsdk.operator.api.config.ControllerConfigurationOverrider; import lombok.extern.slf4j.Slf4j; @@ -73,7 +71,6 @@ public class SparkOperator { private final SparkClusterSubmissionWorker clusterSubmissionWorker; private final SparkAppStatusRecorder sparkAppStatusRecorder; private final SparkClusterStatusRecorder sparkClusterStatusRecorder; - protected Set> registeredSparkControllers; protected Set watchedNamespaces; private final MetricsSystem metricsSystem; private final SentinelManager sparkApplicationSentinelManager; @@ -95,7 +92,6 @@ public SparkOperator() { this.sparkAppStatusRecorder = new SparkAppStatusRecorder(getAppStatusListener(), recorderSource); this.sparkClusterStatusRecorder = new SparkClusterStatusRecorder(getClusterStatusListener()); - this.registeredSparkControllers = new HashSet<>(); this.watchedNamespaces = getWatchedNamespaces(); this.sparkApplicationSentinelManager = new SentinelManager<>(); this.sparkClusterSentinelManager = new SentinelManager<>(); @@ -161,16 +157,14 @@ static void runSystemGc() { */ protected Operator registerSparkOperator() { Operator op = new Operator(this::overrideOperatorConfigs); - registeredSparkControllers.add( - op.register( - new SparkAppReconciler( - appSubmissionWorker, sparkAppStatusRecorder, sparkApplicationSentinelManager), - this::overrideControllerConfigs)); - registeredSparkControllers.add( - op.register( - new SparkClusterReconciler( - clusterSubmissionWorker, sparkClusterStatusRecorder, sparkClusterSentinelManager), - this::overrideControllerConfigs)); + op.register( + new SparkAppReconciler( + appSubmissionWorker, sparkAppStatusRecorder, sparkApplicationSentinelManager), + this::overrideControllerConfigs); + op.register( + new SparkClusterReconciler( + clusterSubmissionWorker, sparkClusterStatusRecorder, sparkClusterSentinelManager), + this::overrideControllerConfigs); return op; } @@ -188,8 +182,7 @@ protected Operator registerSparkOperatorConfMonitor() { operatorNamespace, confSelector); op.register( - new SparkOperatorConfigMapReconciler( - this::updateWatchingNamespaces, unused -> getWatchedNamespaces()), + new SparkOperatorConfigMapReconciler(), c -> { c.withRateLimiter(SparkOperatorConf.getOperatorRateLimiter()); c.settingNamespaces(operatorNamespace); @@ -198,38 +191,6 @@ protected Operator registerSparkOperatorConfMonitor() { return op; } - /** - * Updates the set of namespaces that the operator is watching. - * - * @param namespaces The new set of namespaces to watch. - * @return True if the namespaces were updated, false otherwise. - */ - protected boolean updateWatchingNamespaces(Set namespaces) { - if (watchedNamespaces.equals(namespaces)) { - log.info("No watched namespace change detected"); - return false; - } - if (watchedNamespaces.isEmpty()) { - log.info("Cannot update watch namespaces for operator started at cluster level."); - return false; - } - if (namespaces == null || namespaces.isEmpty()) { - log.error("Cannot updating namespaces to empty"); - return false; - } - registeredSparkControllers.forEach( - c -> { - if (c.allowsNamespaceChanges()) { - log.info("Updating operator namespaces to {}", namespaces); - c.changeNamespaces(namespaces); - } else { - log.error("Controller does not allow namespace change, skipping namespace change."); - } - }); - this.watchedNamespaces = new HashSet<>(namespaces); - return true; - } - /** * Overrides the default configuration for the operator. * diff --git a/spark-operator/src/main/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconciler.java b/spark-operator/src/main/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconciler.java index 184129d9..5a247e9f 100644 --- a/spark-operator/src/main/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconciler.java +++ b/spark-operator/src/main/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconciler.java @@ -19,29 +19,23 @@ package org.apache.spark.k8s.operator.config; -import java.util.Set; -import java.util.function.Function; - import io.fabric8.kubernetes.api.model.ConfigMap; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; /** * This serves dynamic configuration for Spark Operator. When enabled, Operator assumes config file * is located in given config map. It would keep watch the config map and apply changes when update - * is detected. + * is detected. The set of watched namespaces is intentionally excluded from dynamic refresh and can + * only be changed by restarting the operator with updated Helm values. */ @ControllerConfiguration -@RequiredArgsConstructor @Slf4j public class SparkOperatorConfigMapReconciler implements Reconciler { - private final Function, Boolean> namespaceUpdater; - private final Function> watchedNamespacesGetter; /** * Updates the error status of the ConfigMap reconciliation. @@ -70,7 +64,6 @@ public ErrorStatusUpdateControl updateErrorStatus( public UpdateControl reconcile(ConfigMap resource, Context context) throws Exception { SparkOperatorConfManager.INSTANCE.refresh(resource.getData()); - namespaceUpdater.apply(watchedNamespacesGetter.apply(null)); return UpdateControl.noUpdate(); } } diff --git a/spark-operator/src/test/java/org/apache/spark/k8s/operator/SparkOperatorTest.java b/spark-operator/src/test/java/org/apache/spark/k8s/operator/SparkOperatorTest.java index b8b57998..2380805b 100644 --- a/spark-operator/src/test/java/org/apache/spark/k8s/operator/SparkOperatorTest.java +++ b/spark-operator/src/test/java/org/apache/spark/k8s/operator/SparkOperatorTest.java @@ -26,15 +26,12 @@ import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; import java.util.Set; import java.util.function.Consumer; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.Operator; -import io.javaoperatorsdk.operator.RegisteredController; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.MockedConstruction; @@ -49,7 +46,6 @@ import org.apache.spark.k8s.operator.metrics.source.KubernetesMetricsInterceptor; import org.apache.spark.k8s.operator.probe.ProbeService; import org.apache.spark.k8s.operator.reconciler.SparkAppReconciler; -import org.apache.spark.k8s.operator.reconciler.SparkClusterReconciler; import org.apache.spark.k8s.operator.utils.Utils; class SparkOperatorTest { @@ -85,8 +81,7 @@ void testOperatorConstructionWithDynamicConfigEnabled() { .thenReturn(mockClient); mockUtils.when(Utils::getWatchedNamespaces).thenReturn(Set.of("namespace-1")); - SparkOperator sparkOperator = new SparkOperator(); - Assertions.assertEquals(1, sparkOperator.registeredSparkControllers.size()); + new SparkOperator(); Assertions.assertEquals(2, operatorConstruction.constructed().size()); Assertions.assertEquals(1, sparkAppReconcilerConstruction.constructed().size()); Assertions.assertEquals(1, configReconcilerConstruction.constructed().size()); @@ -128,8 +123,7 @@ void testOperatorConstructionWithDynamicConfigDisabled() { mockKubernetesClientFactory .when(() -> KubernetesClientFactory.buildKubernetesClient(any())) .thenReturn(mockClient); - SparkOperator sparkOperator = new SparkOperator(); - Assertions.assertEquals(1, sparkOperator.registeredSparkControllers.size()); + new SparkOperator(); Assertions.assertEquals(1, operatorConstruction.constructed().size()); Assertions.assertEquals(1, sparkAppReconcilerConstruction.constructed().size()); Assertions.assertEquals(1, probeServiceConstruction.constructed().size()); @@ -140,57 +134,4 @@ void testOperatorConstructionWithDynamicConfigDisabled() { setConfigKey(SparkOperatorConf.DYNAMIC_CONFIG_ENABLED, dynamicConfigEnabled); } } - - @SuppressWarnings("PMD.UnusedLocalVariable") - @Test - void testUpdateWatchedNamespacesWithDynamicConfigEnabled() { - MetricsSystem mockMetricsSystem = mock(MetricsSystem.class); - KubernetesClient mockClient = mock(KubernetesClient.class); - var registeredController = mock(RegisteredController.class); - when(registeredController.allowsNamespaceChanges()).thenReturn(true); - boolean dynamicConfigEnabled = SparkOperatorConf.DYNAMIC_CONFIG_ENABLED.getValue(); - - try (MockedStatic mockMetricsSystemFactory = - mockStatic(MetricsSystemFactory.class); - MockedStatic mockKubernetesClientFactory = - mockStatic(KubernetesClientFactory.class); - MockedStatic mockUtils = mockStatic(Utils.class); - MockedConstruction operatorConstruction = - mockConstruction( - Operator.class, - (mock, context) -> { - when(mock.register(any(SparkAppReconciler.class), any(Consumer.class))) - .thenReturn(registeredController); - when(mock.register(any(SparkClusterReconciler.class), any(Consumer.class))) - .thenReturn(registeredController); - }); - MockedConstruction sparkAppReconcilerConstruction = - mockConstruction(SparkAppReconciler.class); - MockedConstruction configReconcilerConstruction = - mockConstruction(SparkOperatorConfigMapReconciler.class); - MockedConstruction probeServiceConstruction = - mockConstruction(ProbeService.class); - MockedConstruction metricsServiceConstruction = - mockConstruction(MetricsService.class); - MockedConstruction interceptorMockedConstruction = - mockConstruction(KubernetesMetricsInterceptor.class)) { - setConfigKey(SparkOperatorConf.DYNAMIC_CONFIG_ENABLED, true); - mockMetricsSystemFactory - .when(MetricsSystemFactory::createMetricsSystem) - .thenReturn(mockMetricsSystem); - mockKubernetesClientFactory - .when(() -> KubernetesClientFactory.buildKubernetesClient(any())) - .thenReturn(mockClient); - mockUtils.when(Utils::getWatchedNamespaces).thenReturn(Set.of("namespace-1")); - SparkOperator sparkOperator = new SparkOperator(); - Set updatedNamespaces = Set.of("namespace-1", "namespace-2"); - Assertions.assertTrue(sparkOperator.updateWatchingNamespaces(updatedNamespaces)); - Assertions.assertEquals(updatedNamespaces, sparkOperator.watchedNamespaces); - verify(registeredController).allowsNamespaceChanges(); - verify(registeredController).changeNamespaces(updatedNamespaces); - verifyNoMoreInteractions(registeredController); - } finally { - setConfigKey(SparkOperatorConf.DYNAMIC_CONFIG_ENABLED, dynamicConfigEnabled); - } - } } diff --git a/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java b/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java index d8f81e79..9d7b2633 100644 --- a/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java +++ b/spark-operator/src/test/java/org/apache/spark/k8s/operator/config/SparkOperatorConfigMapReconcilerTest.java @@ -22,10 +22,8 @@ import static org.apache.spark.k8s.operator.config.SparkOperatorConf.RECONCILER_INTERVAL_SECONDS; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -import static org.mockito.Mockito.mock; import java.util.Map; -import java.util.function.Function; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.fabric8.kubeapitest.junit.EnableKubeAPIServer; @@ -50,10 +48,8 @@ class SparkOperatorConfigMapReconcilerTest { Operator operator; @BeforeEach - @SuppressWarnings("unchecked") void startController() { - var reconciler = - new SparkOperatorConfigMapReconciler(mock(Function.class), mock(Function.class)); + var reconciler = new SparkOperatorConfigMapReconciler(); operator = new Operator(o -> o.withKubernetesClient(client)); operator.register(reconciler); operator.start(); diff --git a/tests/e2e/helm/dynamic-config-values-2.yaml b/tests/e2e/helm/dynamic-config-values-2.yaml deleted file mode 100644 index b6410cb1..00000000 --- a/tests/e2e/helm/dynamic-config-values-2.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -workloadResources: - namespaces: - overrideWatchedNamespaces: false - data: - - "spark-3" - role: - create: true - roleBinding: - create: true - clusterRole: - name: spark-workload-clusterrole-2 - -operatorConfiguration: - dynamicConfig: - enable: true - create: true - data: - spark.kubernetes.operator.watchedNamespaces: "spark-3" - -operatorRbac: - clusterRole: - name: "spark-operator-clusterrole-2" - clusterRoleBinding: - name: "spark-operator-clusterrolebinding-2" diff --git a/tests/e2e/watched-namespaces/chainsaw-test.yaml b/tests/e2e/watched-namespaces/chainsaw-test.yaml deleted file mode 100644 index 95d4a004..00000000 --- a/tests/e2e/watched-namespaces/chainsaw-test.yaml +++ /dev/null @@ -1,122 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: chainsaw.kyverno.io/v1alpha1 -kind: Test -metadata: - name: spark-operator-dynamic-configuration-validation -spec: - steps: - - try: - - apply: - file: spark-operator-dynamic-config-1.yaml - - sleep: - duration: 30s - - script: - content: - kubectl logs -n default $(kubectl get pods -o=name -l app.kubernetes.io/component=operator-deployment,app.kubernetes.io/name=spark-kubernetes-operator) - check: - (contains($stdout, 'Updating operator namespaces to [default, spark-1]')): true - - apply: - bindings: - - name: SPARK_APP_NAMESPACE - value: spark-1 - file: spark-example.yaml - - assert: - bindings: - - name: SPARK_APP_NAMESPACE - value: spark-1 - timeout: 60s - file: "../assertions/spark-application/spark-state-transition.yaml" - - apply: - bindings: - - name: SPARK_APP_NAMESPACE - value: spark-2 - file: spark-example.yaml - - sleep: - duration: 60s - - script: - content: - kubectl get sparkapplication spark-job-succeeded-test -n spark-2 -o json | jq ".status" - check: - (contains($stdout, 'null')): true - catch: - - podLogs: - namespace: default - selector: app.kubernetes.io/component=operator-deployment,app.kubernetes.io/name=spark-kubernetes-operator - - describe: - apiVersion: spark.apache.org/v1 - kind: SparkApplication - namespace: spark-1 - - describe: - apiVersion: spark.apache.org/v1 - kind: SparkApplication - namespace: spark-2 - finally: - - script: - content: | - kubectl delete sparkapplication spark-job-succeeded-test -n spark-1 --ignore-not-found=true - kubectl delete sparkapplication spark-job-succeeded-test -n spark-2 --ignore-not-found=true - kubectl replace -f spark-operator-dynamic-config-2.yaml - - try: - - script: - content: | - echo "Installing another spark operator in default-2 namespaces, watching on namespace: spark-3" - helm install spark -n default-2 --create-namespace -f \ - ../../../build-tools/helm/spark-kubernetes-operator/values.yaml -f \ - ../helm/dynamic-config-values-2.yaml \ - ../../../build-tools/helm/spark-kubernetes-operator/ - - apply: - bindings: - - name: SPARK_APP_NAMESPACE - value: spark-3 - file: spark-example.yaml - - sleep: - duration: 60s - - script: - content: - kubectl logs -n default-2 $(kubectl get pods -n default-2 -o=name -l app.kubernetes.io/component=operator-deployment,app.kubernetes.io/name=spark-kubernetes-operator) - check: - (contains($stdout, 'Updating operator namespaces to [spark-3]')): true - - assert: - bindings: - - name: SPARK_APP_NAMESPACE - value: spark-3 - timeout: 180s - file: "../assertions/spark-application/spark-state-transition.yaml" - catch: - - podLogs: - namespace: default-2 - selector: app.kubernetes.io/component=operator-deployment,app.kubernetes.io/name=spark-kubernetes-operator - - describe: - apiVersion: spark.apache.org/v1 - kind: SparkApplication - namespace: spark-3 - - get: - apiVersion: v1 - kind: Pod - namespace: spark-3 - - events: - namespace: spark-3 - finally: - - script: - timeout: 60s - content: | - kubectl delete sparkapplication spark-job-succeeded-test -n spark-3 --ignore-not-found=true - helm uninstall spark-kubernetes-operator -n default-2 - kubectl delete namespace default-2 --ignore-not-found=true - kubectl delete namespace spark-3 --ignore-not-found=true diff --git a/tests/e2e/watched-namespaces/spark-example.yaml b/tests/e2e/watched-namespaces/spark-example.yaml deleted file mode 100644 index 54c798f4..00000000 --- a/tests/e2e/watched-namespaces/spark-example.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: spark.apache.org/v1 -kind: SparkApplication -metadata: - name: spark-job-succeeded-test - namespace: ($SPARK_APP_NAMESPACE) -spec: - mainClass: "org.apache.spark.examples.SparkPi" - jars: "local:///opt/spark/examples/jars/spark-examples.jar" - sparkConf: - spark.executor.instances: "1" - spark.kubernetes.container.image: "apache/spark:{{SPARK_VERSION}}-scala" - spark.kubernetes.authenticate.driver.serviceAccountName: "spark" - runtimeVersions: - sparkVersion: "4.1.2" diff --git a/tests/e2e/watched-namespaces/spark-operator-dynamic-config-1.yaml b/tests/e2e/watched-namespaces/spark-operator-dynamic-config-1.yaml deleted file mode 100644 index da1f1f31..00000000 --- a/tests/e2e/watched-namespaces/spark-operator-dynamic-config-1.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: v1 -data: - spark.kubernetes.operator.watchedNamespaces: default, spark-1 -kind: ConfigMap -metadata: - annotations: - helm.sh/resource-policy: keep - meta.helm.sh/release-name: spark-kubernetes-operator - meta.helm.sh/release-namespace: default - labels: - app.kubernetes.io/component: operator-dynamic-config-overrides - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: spark-kubernetes-operator - app.kubernetes.io/version: 1.0.0-SNAPSHOT - helm.sh/chart: spark-kubernetes-operator-1.8.0-dev - name: spark-kubernetes-operator-dynamic-configuration - namespace: default diff --git a/tests/e2e/watched-namespaces/spark-operator-dynamic-config-2.yaml b/tests/e2e/watched-namespaces/spark-operator-dynamic-config-2.yaml deleted file mode 100644 index 510d78b1..00000000 --- a/tests/e2e/watched-namespaces/spark-operator-dynamic-config-2.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -apiVersion: v1 -data: - spark.kubernetes.operator.watchedNamespaces: default -kind: ConfigMap -metadata: - annotations: - helm.sh/resource-policy: keep - meta.helm.sh/release-name: spark-kubernetes-operator - meta.helm.sh/release-namespace: default - labels: - app.kubernetes.io/component: operator-dynamic-config-overrides - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: spark-kubernetes-operator - app.kubernetes.io/version: 1.0.0-SNAPSHOT - helm.sh/chart: spark-kubernetes-operator-1.8.0-dev - name: spark-kubernetes-operator-dynamic-configuration - namespace: default