Skip to content
Snippets Groups Projects
Commit 10508f36 authored by Jo Voordeckers's avatar Jo Voordeckers Committed by Andrew Or
Browse files

[SPARK-11327][MESOS] Dispatcher does not respect all args from the Submit request

Supersedes https://github.com/apache/spark/pull/9752

Author: Jo Voordeckers <jo.voordeckers@gmail.com>
Author: Iulian Dragos <jaguarul@gmail.com>

Closes #10370 from jayv/mesos_cluster_params.
parent 0abee534
No related branches found
No related tags found
No related merge requests found
...@@ -423,6 +423,12 @@ private[spark] class MesosClusterScheduler( ...@@ -423,6 +423,12 @@ private[spark] class MesosClusterScheduler(
"--driver-cores", desc.cores.toString, "--driver-cores", desc.cores.toString,
"--driver-memory", s"${desc.mem}M") "--driver-memory", s"${desc.mem}M")
val replicatedOptionsBlacklist = Set(
"spark.jars", // Avoids duplicate classes in classpath
"spark.submit.deployMode", // this would be set to `cluster`, but we need client
"spark.master" // this contains the address of the dispatcher, not master
)
// Assume empty main class means we're running python // Assume empty main class means we're running python
if (!desc.command.mainClass.equals("")) { if (!desc.command.mainClass.equals("")) {
options ++= Seq("--class", desc.command.mainClass) options ++= Seq("--class", desc.command.mainClass)
...@@ -440,9 +446,29 @@ private[spark] class MesosClusterScheduler( ...@@ -440,9 +446,29 @@ private[spark] class MesosClusterScheduler(
.mkString(",") .mkString(",")
options ++= Seq("--py-files", formattedFiles) options ++= Seq("--py-files", formattedFiles)
} }
desc.schedulerProperties
.filter { case (key, _) => !replicatedOptionsBlacklist.contains(key) }
.foreach { case (key, value) => options ++= Seq("--conf", s"$key=${shellEscape(value)}") }
options options
} }
/**
* Escape args for Unix-like shells, unless already quoted by the user.
* Based on: http://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
* and http://www.grymoire.com/Unix/Quote.html
* @param value argument
* @return escaped argument
*/
private[scheduler] def shellEscape(value: String): String = {
val WrappedInQuotes = """^(".+"|'.+')$""".r
val ShellSpecialChars = (""".*([ '<>&|\?\*;!#\\(\)"$`]).*""").r
value match {
case WrappedInQuotes(c) => value // The user quoted his args, don't touch it!
case ShellSpecialChars(c) => "\"" + value.replaceAll("""(["`\$\\])""", """\\$1""") + "\""
case _: String => value // Don't touch harmless strings
}
}
private class ResourceOffer( private class ResourceOffer(
val offerId: OfferID, val offerId: OfferID,
val slaveId: SlaveID, val slaveId: SlaveID,
......
...@@ -136,4 +136,40 @@ class MesosClusterSchedulerSuite extends SparkFunSuite with LocalSparkContext wi ...@@ -136,4 +136,40 @@ class MesosClusterSchedulerSuite extends SparkFunSuite with LocalSparkContext wi
capture.capture() capture.capture()
) )
} }
test("escapes commandline args for the shell") {
val conf = new SparkConf()
conf.setMaster("mesos://localhost:5050")
conf.setAppName("spark mesos")
val scheduler = new MesosClusterScheduler(
new BlackHoleMesosClusterPersistenceEngineFactory, conf) {
override def start(): Unit = { ready = true }
}
val escape = scheduler.shellEscape _
def wrapped(str: String): String = "\"" + str + "\""
// Wrapped in quotes
assert(escape("'should be left untouched'") === "'should be left untouched'")
assert(escape("\"should be left untouched\"") === "\"should be left untouched\"")
// Harmless
assert(escape("") === "")
assert(escape("harmless") === "harmless")
assert(escape("har-m.l3ss") === "har-m.l3ss")
// Special Chars escape
assert(escape("should escape this \" quote") === wrapped("should escape this \\\" quote"))
assert(escape("shouldescape\"quote") === wrapped("shouldescape\\\"quote"))
assert(escape("should escape this $ dollar") === wrapped("should escape this \\$ dollar"))
assert(escape("should escape this ` backtick") === wrapped("should escape this \\` backtick"))
assert(escape("""should escape this \ backslash""")
=== wrapped("""should escape this \\ backslash"""))
assert(escape("""\"?""") === wrapped("""\\\"?"""))
// Special Chars no escape only wrap
List(" ", "'", "<", ">", "&", "|", "?", "*", ";", "!", "#", "(", ")").foreach(char => {
assert(escape(s"onlywrap${char}this") === wrapped(s"onlywrap${char}this"))
})
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment