Skip to content

Commit

Permalink
Run chmod +x explicitly in stage0 (#1201)
Browse files Browse the repository at this point in the history
* Run chmod +x explicitly in stage0

Using sbt-native-packager 1.3.17 with OpenShift, I still ran into some permission issues and needed to call chmod +x explicitly in the container. This will emit chmod +x for all bash scripts that was generated.

* Add full default permission type
  • Loading branch information
eed3si9n authored and muuki88 committed Feb 12, 2019
1 parent dc6a7ea commit b8b9f2d
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ sealed trait DockerChmodType {
}
object DockerChmodType {

/**
* Gives read permission to users and groups.
*/
case object UserGroupRead extends DockerChmodType {
def argument: String = "u=r,g=r"
}

/**
* Gives read permission to users and groups.
* Gives execute permission to users and groups, if +x flag is on for any.
Expand All @@ -61,6 +68,13 @@ object DockerChmodType {
def argument: String = "u=rwX,g=rwX"
}

/**
* Gives +x permission to users and groups.
*/
case object UserGroupPlusExecute extends DockerChmodType {
def argument: String = "u+x,g+x"
}

/**
* Copies user file mode bits to group file mode bits.
*/
Expand Down
33 changes: 27 additions & 6 deletions src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ object DockerPlugin extends AutoPlugin {
},
dockerRmiCommand := dockerExecCommand.value ++ Seq("rmi"),
dockerBuildCommand := dockerExecCommand.value ++ Seq("build") ++ dockerBuildOptions.value ++ Seq("."),
dockerAdditionalPermissions := {
val scripts = makeBashScripts.value
val ms = (mappings in Docker).value
scripts flatMap {
case (script, _) =>
ms collect {
case (k, v) if k == script => DockerChmodType.UserGroupPlusExecute -> v
}
}
},
dockerCommands := {
val strategy = dockerPermissionStrategy.value
val dockerBaseDirectory = (defaultLinuxInstallLocation in Docker).value
Expand All @@ -116,6 +126,7 @@ object DockerPlugin extends AutoPlugin {
val group = (daemonGroup in Docker).value
val gidOpt = (daemonGroupGid in Docker).value
val base = dockerBaseImage.value
val addPerms = dockerAdditionalPermissions.value

val generalCommands = makeFrom(base) +: makeMaintainer((maintainer in Docker).value).toSeq
val stage0name = "stage0"
Expand All @@ -126,9 +137,10 @@ object DockerPlugin extends AutoPlugin {
makeWorkdir(dockerBaseDirectory),
makeCopy(dockerBaseDirectory),
makeUser("root"),
makeChmod(dockerChmodType.value, Seq(dockerBaseDirectory)),
DockerStageBreak
)
makeChmodRecursive(dockerChmodType.value, Seq(dockerBaseDirectory))
) ++
(addPerms map { case (tpe, v) => makeChmod(tpe, Seq(v)) }) ++
Seq(DockerStageBreak)
case _ => Seq()
}

Expand All @@ -142,7 +154,8 @@ object DockerPlugin extends AutoPlugin {
case DockerPermissionStrategy.MultiStage =>
Seq(makeCopyFrom(dockerBaseDirectory, stage0name, user, group))
case DockerPermissionStrategy.Run =>
Seq(makeCopy(dockerBaseDirectory), makeChmod(dockerChmodType.value, Seq(dockerBaseDirectory)))
Seq(makeCopy(dockerBaseDirectory), makeChmodRecursive(dockerChmodType.value, Seq(dockerBaseDirectory))) ++
(addPerms map { case (tpe, v) => makeChmod(tpe, Seq(v)) })
case DockerPermissionStrategy.CopyChown =>
Seq(makeCopyChown(dockerBaseDirectory, user, group))
case DockerPermissionStrategy.None =>
Expand All @@ -156,6 +169,8 @@ object DockerPlugin extends AutoPlugin {
case Some(uid) => makeUser(uid)
case _ => makeUser(user)
}) ++
// Use this to debug permissions
// Seq(ExecCmd("RUN", Seq("ls", "-l", "/opt/docker/bin/"): _*)) ++
Seq(makeEntrypoint(dockerEntrypoint.value), makeCmd(dockerCmd.value))

stage0 ++ stage1
Expand Down Expand Up @@ -321,9 +336,15 @@ object DockerPlugin extends AutoPlugin {
ExecCmd("RUN", Seq("chown", "-R", s"$daemonUser:$daemonGroup") ++ directories: _*)

/**
* @return chown command, owning the installation directory with the daemonuser
* @return chmod command
*/
private final def makeChmod(chmodType: DockerChmodType, files: Seq[String]): CmdLike =
ExecCmd("RUN", Seq("chmod", chmodType.argument) ++ files: _*)

/**
* @return chmod command recursively
*/
private final def makeChmod(chmodType: DockerChmodType, directories: Seq[String]): CmdLike =
private final def makeChmodRecursive(chmodType: DockerChmodType, directories: Seq[String]): CmdLike =
ExecCmd("RUN", Seq("chmod", "-R", chmodType.argument) ++ directories: _*)

/**
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/com/typesafe/sbt/packager/docker/Keys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@ trait DockerKeys {
private[packager] trait DockerKeysEx extends DockerKeys {
lazy val dockerPermissionStrategy = settingKey[DockerPermissionStrategy]("The strategy to change file permissions.")
lazy val dockerChmodType = settingKey[DockerChmodType]("The file permissions for the files copied into Docker image.")
lazy val dockerAdditionalPermissions =
taskKey[Seq[(DockerChmodType, String)]]("Explicit chmod calls to some of the paths.")
}
5 changes: 5 additions & 0 deletions src/sbt-test/docker/file-permission/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package example

object Main extends App {
println("hello")
}
3 changes: 3 additions & 0 deletions src/sbt-test/docker/file-permission/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ lazy val root = (project in file("."))
|COPY opt /opt
|USER root
|RUN ["chmod", "-R", "u=rX,g=rX", "/opt/docker"]
|RUN ["chmod", "u+x,g+x", "/opt/docker/bin/file-permission-test"]
|
|FROM fabric8/java-centos-openjdk8-jdk
|USER root
Expand Down Expand Up @@ -53,6 +54,7 @@ lazy val root = (project in file("."))
|WORKDIR /opt/docker
|COPY opt /opt
|RUN ["chmod", "-R", "u=rX,g=rX", "/opt/docker"]
|RUN ["chmod", "u+x,g+x", "/opt/docker/bin/file-permission-test"]
|USER 1001
|ENTRYPOINT ["/opt/docker/bin/file-permission-test"]
|CMD []""".stripMargin.linesIterator.toList)
Expand All @@ -79,6 +81,7 @@ lazy val root = (project in file("."))
|COPY opt /opt
|USER root
|RUN ["chmod", "-R", "u=rwX,g=rwX", "/opt/docker"]
|RUN ["chmod", "u+x,g+x", "/opt/docker/bin/file-permission-test"]
|
|FROM fabric8/java-centos-openjdk8-jdk
|USER root
Expand Down
21 changes: 17 additions & 4 deletions src/sphinx/formats/docker.rst
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,16 @@ Environment Settings
``dockerChmodType``
The file permissions for the files copied into Docker image when ``MultiStage`` or ``Run`` strategy is used.

* ``DockerChmodType.UserGroupReadExecute`` (default): chmod -R u=rX,g=rX
* ``DockerChmodType.UserGroupWriteExecute``: chmod -R u=rwX,g=rwX
* ``DockerChmodType.SyncGroupToUser``: chmod -R g=u
* ``DockerChmodType.UserGroupReadExecute`` (default): chmod u=rX,g=rX
* ``DockerChmodType.UserGroupRead``: chmod u=r,g=r
* ``DockerChmodType.UserGroupWriteExecute``: chmod u=rwX,g=rwX
* ``DockerChmodType.SyncGroupToUser``: chmod g=u
* ``DockerChmodType.UserGroupPlusExecute``: chmod u+x,g+x (This is for ``dockerAdditionalPermissions``)
* ``DockerChmodType.Custom``: Custom argument provided by the user.

``dockerAdditionalPermissions``
Additional permissions typically used to give ``chmod +x`` rights for the executable files. By default generated Bash scripts are given ``DockerChmodType.UserGroupPlusExecute``.

``dockerVersion``
The docker server version. Used to leverage new docker features while maintaining backwards compatibility.

Expand Down Expand Up @@ -271,6 +276,14 @@ If you want to make the working directory writable by the running process, here'
dockerChmodType := DockerChmodType.UserGroupWriteExecute
By default, the shell scripts generated by SBT Native Packager are given ``chmod +x`` rights. Here's the setting to do so for other files:

.. code-block:: scala
import com.typesafe.sbt.packager.docker.DockerChmodType
dockerAdditionalPermissions += (DockerChmodType.UserGroupPlusExecute, "/opt/docker/bin/hello")
If you don't want SBT Native Packager to change the file permissions at all here's a strategy you can choose:

.. code-block:: scala
Expand All @@ -280,7 +293,7 @@ If you don't want SBT Native Packager to change the file permissions at all here
dockerPermissionStrategy := DockerPermissionStrategy.None
This will inherit the file mode bits set in your machine. Given that Kubernetes implementations like OpenShift will use an arbitrary user,
remember to set both the user bits and group bits when running `chmod` yourself.
remember to set both the user bits and group bits when running ``chmod`` yourself.

Custom Dockerfile
~~~~~~~~~~~~~~~~~
Expand Down

0 comments on commit b8b9f2d

Please sign in to comment.