Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for --chown flag for ADD/COPY Docker commands #1044

Merged
merged 5 commits into from
Oct 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import com.typesafe.sbt.SbtNativePackager.Universal
import com.typesafe.sbt.packager.Compat._
import com.typesafe.sbt.packager.{MappingsHelper, Stager}

import scala.sys.process.Process
import scala.util.Try

/**
* == Docker Plugin ==
*
Expand Down Expand Up @@ -80,6 +83,9 @@ object DockerPlugin extends AutoPlugin {
dockerEntrypoint := Seq("bin/%s" format executableScriptName.value),
dockerCmd := Seq(),
dockerExecCommand := Seq("docker"),
dockerVersion := Try(Process(dockerExecCommand.value ++ Seq("version --format '{{.Server.Version}}'")).!!)
Copy link
Contributor

@NeQuissimus NeQuissimus Oct 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guys, I don't think this works...
I believe it needs to be Seq("version", "--format", "'{{.Server.Version}}'"), otherwise your shell will add another set of ticks around the whole thing and Docker will report that it does not know the command.

I will try to confirm this and send a PR is necessary. I'd love to use this feature :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm me, already fixed somewhere else :D

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1052 and @mrfyda ftw! :D

.toOption.map(_.trim)
.flatMap(DockerVersion.parse),
dockerBuildOptions := Seq("--force-rm") ++ Seq("-t", dockerAlias.value.versioned) ++ (
if (dockerUpdateLatest.value)
Seq("-t", dockerAlias.value.latest)
Expand All @@ -96,7 +102,7 @@ object DockerPlugin extends AutoPlugin {
val generalCommands = makeFrom(dockerBaseImage.value) +: makeMaintainer((maintainer in Docker).value).toSeq

generalCommands ++
Seq(makeWorkdir(dockerBaseDirectory), makeAdd(dockerBaseDirectory), makeChown(user, group, "." :: Nil)) ++
Seq(makeWorkdir(dockerBaseDirectory)) ++ makeAdd(dockerVersion.value, dockerBaseDirectory, user, group) ++
dockerLabels.value.map(makeLabel) ++
makeExposePorts(dockerExposedPorts.value, dockerExposedUdpPorts.value) ++
makeVolumes(dockerExposedVolumes.value, user, group) ++
Expand Down Expand Up @@ -179,18 +185,32 @@ object DockerPlugin extends AutoPlugin {
Cmd("WORKDIR", dockerBaseDirectory)

/**
* @param dockerBaseDirectory, the installation directory
* @param dockerVersion
* @param dockerBaseDirectory the installation directory
* @param daemonUser
* @param daemonGroup
* @return ADD command adding all files inside the installation directory
*/
private final def makeAdd(dockerBaseDirectory: String): CmdLike = {
private final def makeAdd(dockerVersion: Option[DockerVersion], dockerBaseDirectory: String,
daemonUser: String, daemonGroup: String): Seq[CmdLike] = {

/**
* This is the file path of the file in the Docker image, and does not depend on the OS where the image
* is being built. This means that it needs to be the Unix file separator even when the image is built
* on e.g. Windows systems.
*/
val files = dockerBaseDirectory.split(UnixSeparatorChar)(1)
Cmd("ADD", s"$files /$files")

if (dockerVersion.exists(DockerSupport.chownFlag)) {
Seq(
Cmd("ADD", s"--chown=$daemonUser:$daemonGroup $files /$files")
)
} else {
Seq(
Cmd("ADD", s"$files /$files"),
makeChown(daemonUser, daemonGroup, "." :: Nil)
)
}
}

/**
Expand Down Expand Up @@ -278,7 +298,7 @@ object DockerPlugin extends AutoPlugin {
}

/**
* uses the `mappings in Unversial` to generate the
* uses the `mappings in Universal` to generate the
* `mappings in Docker`.
*/
def mapGenericFilesToDocker: Seq[Setting[_]] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ object DockerSpotifyClientPlugin extends AutoPlugin {

override lazy val projectSettings: Seq[Setting[_]] = inConfig(Docker)(clientSettings)

def clientSettings = Seq(publishLocal := publishLocalDocker.value)
def clientSettings = Seq(
publishLocal := publishLocalDocker.value,
dockerVersion := dockerServerVersion.value
)

def publishLocalDocker: Def.Initialize[Task[Unit]] = Def.task {
val context = stage.value
Expand All @@ -81,4 +84,9 @@ object DockerSpotifyClientPlugin extends AutoPlugin {
}
}

def dockerServerVersion: Def.Initialize[Option[DockerVersion]] = Def.setting {
val docker: DockerClient = DefaultDockerClient.fromEnv().build()
DockerVersion.parse(docker.version().version())
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.typesafe.sbt.packager.docker

object DockerSupport {

def chownFlag(version: DockerVersion): Boolean = {
(version.major == 17 && version.minor >= 9) || version.major > 17
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.typesafe.sbt.packager.docker

import scala.util.matching.Regex


case class DockerVersion(major: Int, minor: Int, patch: Int, release: Option[String])

object DockerVersion {
private val DockerVersionPattern: Regex = "^'?([0-9]+).([0-9]+).([0-9]+)-?([-a-z]+)?'?$".r

def parse(version: String): Option[DockerVersion] = {
Option(version).collect {
case DockerVersionPattern(major, minor, patch, release) =>
new DockerVersion(major.toInt, minor.toInt, patch.toInt, Option(release))
}
}
}
1 change: 1 addition & 0 deletions src/main/scala/com/typesafe/sbt/packager/docker/Keys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ trait DockerKeys {
"Docker CMD. Used together with dockerEntrypoint. Arguments passed in exec form"
)
val dockerExecCommand = SettingKey[Seq[String]]("dockerExecCommand", "The shell command used to exec Docker")
val dockerVersion = SettingKey[Option[DockerVersion]]("dockerVersion", "The docker server version")
val dockerBuildOptions = SettingKey[Seq[String]]("dockerBuildOptions", "Options used for the Docker build")
val dockerBuildCommand = SettingKey[Seq[String]]("dockerBuildCommand", "Command for building the Docker image")
val dockerLabels = SettingKey[Map[String, String]]("dockerLabels", "Labels applied to the Docker image")
Expand Down
5 changes: 4 additions & 1 deletion src/sphinx/formats/docker.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,17 @@ Environment Settings
Overrides the default entrypoint for docker-specific service discovery tasks before running the application.
Defaults to the bash executable script, available at ``bin/<script name>`` in the current ``WORKDIR`` of ``/opt/docker``.

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

Publishing Settings
~~~~~~~~~~~~~~~~~~~

``dockerRepository``
The repository to which the image is pushed when the ``docker:publish`` task is run. This should be of the form ``[repository.host[:repository.port]]`` (assumes use of the ``index.docker.io`` repository) or ``[repository.host[:repository.port]][/username]`` (discouraged, but available for backwards compatibilty.).

``dockerUsername``
The username or orgranization to which the image is pushed when the ``docker:publish`` task is run. This should be of the form ``[username]`` or ``[organization]``.
The username or organization to which the image is pushed when the ``docker:publish`` task is run. This should be of the form ``[username]`` or ``[organization]``.

``dockerUpdateLatest``
The flag to automatic update the latest tag when the ``docker:publish`` task is run. Default value is ``FALSE``. In order to use this setting, the minimum docker console version required is 1.10. See https://github.com/sbt/sbt-native-packager/issues/871 for a detailed explanation.
Expand Down