@@ -77,6 +77,8 @@ private[spark] class Client(
77
77
private val serviceAccount = sparkConf.get(" spark.kubernetes.submit.serviceAccountName" ,
78
78
" default" )
79
79
80
+ private val customLabels = sparkConf.get(" spark.kubernetes.driver.labels" , " " )
81
+
80
82
private implicit val retryableExecutionContext = ExecutionContext
81
83
.fromExecutorService(
82
84
Executors .newSingleThreadExecutor(new ThreadFactoryBuilder ()
@@ -85,6 +87,7 @@ private[spark] class Client(
85
87
.build()))
86
88
87
89
def run (): Unit = {
90
+ val parsedCustomLabels = parseCustomLabels(customLabels)
88
91
var k8ConfBuilder = new ConfigBuilder ()
89
92
.withApiVersion(" v1" )
90
93
.withMasterUrl(master)
@@ -109,14 +112,15 @@ private[spark] class Client(
109
112
.withType(" Opaque" )
110
113
.done()
111
114
try {
112
- val selectors = Map (DRIVER_LAUNCHER_SELECTOR_LABEL -> driverLauncherSelectorValue).asJava
115
+ val resolvedSelectors = (Map (DRIVER_LAUNCHER_SELECTOR_LABEL -> driverLauncherSelectorValue)
116
+ ++ parsedCustomLabels).asJava
113
117
val (servicePorts, containerPorts) = configurePorts()
114
118
val service = kubernetesClient.services().createNew()
115
119
.withNewMetadata()
116
120
.withName(kubernetesAppId)
117
121
.endMetadata()
118
122
.withNewSpec()
119
- .withSelector(selectors )
123
+ .withSelector(resolvedSelectors )
120
124
.withPorts(servicePorts.asJava)
121
125
.endSpec()
122
126
.done()
@@ -137,7 +141,7 @@ private[spark] class Client(
137
141
.asScala
138
142
.find(status =>
139
143
status.getName == DRIVER_LAUNCHER_CONTAINER_NAME && status.getReady) match {
140
- case Some (status ) =>
144
+ case Some (_ ) =>
141
145
try {
142
146
val driverLauncher = getDriverLauncherService(
143
147
k8ClientConfig, master)
@@ -184,7 +188,7 @@ private[spark] class Client(
184
188
kubernetesClient.pods().createNew()
185
189
.withNewMetadata()
186
190
.withName(kubernetesAppId)
187
- .withLabels(selectors )
191
+ .withLabels(resolvedSelectors )
188
192
.endMetadata()
189
193
.withNewSpec()
190
194
.withRestartPolicy(" OnFailure" )
@@ -291,7 +295,7 @@ private[spark] class Client(
291
295
292
296
Utils .tryWithResource(kubernetesClient
293
297
.pods()
294
- .withLabels(selectors )
298
+ .withLabels(resolvedSelectors )
295
299
.watch(podWatcher)) { createDriverPod }
296
300
} finally {
297
301
kubernetesClient.secrets().delete(secret)
@@ -336,7 +340,7 @@ private[spark] class Client(
336
340
.getOption(" spark.ui.port" )
337
341
.map(_.toInt)
338
342
.getOrElse(DEFAULT_UI_PORT ))
339
- (servicePorts.toSeq , containerPorts.toSeq )
343
+ (servicePorts, containerPorts)
340
344
}
341
345
342
346
private def buildSubmissionRequest (): KubernetesCreateSubmissionRequest = {
@@ -366,7 +370,7 @@ private[spark] class Client(
366
370
uploadedJarsBase64Contents = uploadJarsBase64Contents)
367
371
}
368
372
369
- def compressJars (maybeFilePaths : Option [String ]): Option [TarGzippedData ] = {
373
+ private def compressJars (maybeFilePaths : Option [String ]): Option [TarGzippedData ] = {
370
374
maybeFilePaths
371
375
.map(_.split(" ," ))
372
376
.map(CompressionUtils .createTarGzip(_))
@@ -391,6 +395,23 @@ private[spark] class Client(
391
395
sslSocketFactory = sslContext.getSocketFactory,
392
396
trustContext = trustManager)
393
397
}
398
+
399
+ private def parseCustomLabels (labels : String ): Map [String , String ] = {
400
+ labels.split(" ," ).map(_.trim).filterNot(_.isEmpty).map(label => {
401
+ label.split(" =" , 2 ).toSeq match {
402
+ case Seq (k, v) =>
403
+ require(k != DRIVER_LAUNCHER_SELECTOR_LABEL , " Label with key" +
404
+ s " $DRIVER_LAUNCHER_SELECTOR_LABEL cannot be used in " +
405
+ " spark.kubernetes.driver.labels, as it is reserved for Spark's" +
406
+ " internal configuration." )
407
+ (k, v)
408
+ case _ =>
409
+ throw new SparkException (" Custom labels set by spark.kubernetes.driver.labels" +
410
+ " must be a comma-separated list of key-value pairs, with format <key>=<value>." +
411
+ s " Got label: $label. All labels: $labels" )
412
+ }
413
+ }).toMap
414
+ }
394
415
}
395
416
396
417
private object Client {
0 commit comments