Skip to content

Commit

Permalink
. #477 Fixed permissions on items in the context tar sent to docker d…
Browse files Browse the repository at this point in the history
…aemon to support Windows and mirror what the docker client itself does.

Introduced <permissions> for setting various permission related options.
This extends #477, and allows on windows systems to set the execution bit on all files. Please follow the discussion in #477 for more details.
  • Loading branch information
homeaway-jfriesen authored and rhuss committed Jun 26, 2016
1 parent 2ae4aa0 commit dcc7df6
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 35 deletions.
4 changes: 3 additions & 1 deletion doc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
- Fix for tcp wait when used with Docker for Mac (#430)
- Add warning when assembly is empty when watching a Docker image (#490)
- Add `docker.skip.build`, `docker.skip.run`, `docker.skip.push` properties and renamed `docker.skipTags` to `docker.skip.tag` (#483)

- Add new assembly config options `permissions` for fine tuning permissions in the docker.tar (#477). Deprecated `ignorePermissions`
in favor of a `<permissions>ignore</permissions>`

* **0.15.7** (2016-06-09)
- Add support for '.maven-dockerinclude' for including certain files in plain Dockerfile build ([#471](https://github.com/fabric8io/docker-maven-plugin/issues/471))
- Add support for placeholders in image names.
Expand Down
7 changes: 6 additions & 1 deletion doc/manual/docker-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,12 @@ Here's an example:
the container root (`/`). It is also `false` by default when a base image is used with `from`
since exporting makes no sense in this case and will waste disk space unnecessarily.
* **ignorePermissions** indicates if existing file permissions should be ignored
when creating the assembly archive. This value is `false` by default.
when creating the assembly archive with a mode `dir`. This value is `false` by default. This property is
deprecated, use a `permissionMode` of `ignore` instead.
* **permissions** can be `ignore` to use the permission as found on files regardless on any
assembly configuration, `keep` to respect the assembly provided permissions, `exec` for setting
the executable bit on all files (required for Windows when using an assembly mode `dir`) or `auto` to let the
plugin select `exec` on Windows and `keep` on others. `keep` is the default value.
* **mode** specifies how the assembled files should be collected. By default the files a simply
copied (`dir`), but can be set to be a Tar- (`tar`), compressed Tar- (`tgz`) or Zip- (`zip`) Archive.
The archive formats have the advantage that file permission can be preserved better (since the copying is
Expand Down
6 changes: 5 additions & 1 deletion doc/manual/external-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ values in the `<build>` and `<run>` sections.
use.
* **docker.assembly.exportBaseDir** If `true` export base directory
* **docker.assembly.ignorePermissions** If set to `true` existing file permissions are ignored
when creating the assembly archive
when creating the assembly archive. Deprecated, use a permission mode of `ignore` instead.
* **docker.assembly.permissions** can be `ignore` to use the permission as found on files regardless on any
assembly configuration, `keep` to respect the assembly provided permissions, `exec` for setting
the executable bit on all files (required for Windows when using an assembly mode `dir`) or `auto` to let the
plugin select `exec` on Windows and `keep` on others. `keep` is the default value.
* **docker.assembly.dockerFileDir** specifies a directory containing an external Dockerfile
that will be used to create the image. This is deprecated please use `docker.dockerFileDir` or `docker.dockerFile`
instead.
Expand Down
2 changes: 1 addition & 1 deletion samples/data-jolokia-demo/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
for deploying them. I.e. this image has a script 'deploy-and-run.sh' which exactly
does this. -->
<assembly>
<mode>dir</mode>
<mode>tar</mode>
<user>www-data:www-data:www-data</user>
<descriptor>assembly.xml</descriptor>
</assembly>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package io.fabric8.maven.docker.assembly;
/*
*
* Copyright 2016 Roland Huss
*
* Licensed 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.
*/

import java.io.File;
import java.io.IOException;

import io.fabric8.maven.docker.util.Logger;
import org.codehaus.plexus.archiver.ArchiveEntry;
import org.codehaus.plexus.archiver.ResourceIterator;
import org.codehaus.plexus.archiver.tar.TarArchiver;
import org.codehaus.plexus.archiver.tar.TarLongFileMode;
import org.codehaus.plexus.components.io.resources.PlexusIoResource;
import org.codehaus.plexus.util.StringUtils;

/**
* @author roland
* @since 26/06/16
*/
class AllFilesExecCustomizer implements DockerAssemblyManager.ArchiverCustomizer {
private DockerAssemblyManager.ArchiverCustomizer innerCustomizer;
private Logger log;

AllFilesExecCustomizer(DockerAssemblyManager.ArchiverCustomizer inner, Logger logger) {
innerCustomizer = inner;
this.log = logger;
}

@Override
public TarArchiver customize(TarArchiver archiver) throws IOException {
log.warn("/--------------------- SECURITY WARNING ---------------------\\");
log.warn("|You are building a Docker image with normalized permissions.|");
log.warn("|All files and directories added to build context will have |");
log.warn("|'-rwxr-xr-x' permissions. It is recommended to double check |");
log.warn("|and reset permissions for sensitive files and directories. |");
log.warn("\\------------------------------------------------------------/");

if (innerCustomizer != null) {
archiver = innerCustomizer.customize(archiver);
}

TarArchiver newArchiver = new TarArchiver();
newArchiver.setDestFile(archiver.getDestFile());
newArchiver.setLongfile(TarLongFileMode.posix);

ResourceIterator resources = archiver.getResources();
while (resources.hasNext()) {
ArchiveEntry ae = resources.next();
String fileName = ae.getName();
PlexusIoResource resource = ae.getResource();
String name = StringUtils.replace(fileName, File.separatorChar, '/');

// See docker source:
// https://github.com/docker/docker/blob/3d13fddd2bc4d679f0eaa68b0be877e5a816ad53/pkg/archive/archive_windows.go#L45
int mode = ae.getMode() & 0777;
int newMode = mode;
newMode &= 0755;
newMode |= 0111;

if (newMode != mode) {
log.debug("Changing permissions of '%s' from %o to %o.", name, mode, newMode);
}

newArchiver.addResource(resource, name, newMode);
}

archiver = newArchiver;

return archiver;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package io.fabric8.maven.docker.assembly;

import java.io.File;
import java.io.IOException;
import java.util.*;

import io.fabric8.maven.docker.config.*;
import io.fabric8.maven.docker.util.EnvUtil;
import io.fabric8.maven.docker.util.Logger;
import io.fabric8.maven.docker.util.MojoParameters;
import org.apache.maven.plugin.MojoExecutionException;
Expand All @@ -28,6 +25,13 @@
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
* Tool for creating a docker image tar ball including a Dockerfile for building
* a docker image.
Expand Down Expand Up @@ -65,10 +69,11 @@ public class DockerAssemblyManager {
* @param imageName Name of the image to create (used for creating build directories)
* @param params Mojos parameters (used for finding the directories)
* @param buildConfig configuration for how to build the image
* @param log Logger used to display warning if permissions are to be normalized
* @return file holding the path to the created assembly tar file
* @throws MojoExecutionException
*/
public File createDockerTarArchive(String imageName, MojoParameters params, BuildImageConfiguration buildConfig)
public File createDockerTarArchive(String imageName, MojoParameters params, BuildImageConfiguration buildConfig, Logger log)
throws MojoExecutionException {
BuildDirs buildDirs = createBuildDirs(imageName, params);

Expand All @@ -89,13 +94,14 @@ public File createDockerTarArchive(String imageName, MojoParameters params, Buil
throw new MojoExecutionException("Configured Dockerfile \"" +
buildConfig.getDockerFile() + "\" (resolved to \"" + dockerFile + "\") doesnt exist");
}
// User dedicated Dockerfile from extra
// User dedicated Dockerfile from extra director
customizer = new ArchiverCustomizer() {
@Override
public void customize(TarArchiver archiver) throws IOException {
public TarArchiver customize(TarArchiver archiver) throws IOException {
DefaultFileSet fileSet = DefaultFileSet.fileSet(dockerFile.getParentFile());
addDockerIgnoreIfPresent(fileSet);
archiver.addFileSet(fileSet);
return archiver;
}
};
} else {
Expand All @@ -106,12 +112,22 @@ public void customize(TarArchiver archiver) throws IOException {
final File dockerFile = new File(buildDirs.getOutputDirectory(),"Dockerfile");
customizer = new ArchiverCustomizer() {
@Override
public void customize(TarArchiver archiver) throws IOException {
public TarArchiver customize(TarArchiver archiver) throws IOException {
archiver.addFile(dockerFile, "Dockerfile");
return archiver;
}
};
}

// If required make all files in the assembly executable
if (assemblyConfig != null) {
AssemblyConfiguration.PermissionMode mode = assemblyConfig.getPermissions();
if (mode == AssemblyConfiguration.PermissionMode.exec ||
mode == AssemblyConfiguration.PermissionMode.auto && EnvUtil.isWindows()) {
customizer = new AllFilesExecCustomizer(customizer, log);
}
}

return createBuildTarBall(buildDirs, customizer, assemblyMode, buildConfig.getCompression());

} catch (IOException e) {
Expand Down Expand Up @@ -186,9 +202,9 @@ private File createBuildTarBall(BuildDirs buildDirs, ArchiverCustomizer archiver
File archive = new File(buildDirs.getTemporaryRootDirectory(), "docker-build." + compression.getFileSuffix());
try {
TarArchiver archiver = createBuildArchiver(buildDirs.getOutputDirectory(), archive, buildMode);
archiverCustomizer.customize(archiver);
archiver.createArchive();
archiver = archiverCustomizer.customize(archiver);
archiver.setCompression(compression.getTarCompressionMethod());
archiver.createArchive();
return archive;
} catch (NoSuchArchiverException e) {
throw new MojoExecutionException("No archiver for type 'tar' found", e);
Expand Down Expand Up @@ -365,10 +381,9 @@ private Assembly extractAssembly(AssemblerConfigurationSource config) throws Moj
}
}



// Archiver used to adapt for customizations
private interface ArchiverCustomizer {
void customize(TarArchiver archiver) throws IOException;
interface ArchiverCustomizer {
TarArchiver customize(TarArchiver archiver) throws IOException;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class AssemblyConfiguration {

/**
* @paramter default-value="false"
* @deprecated use permissionMode == ignore instead.
*/
private Boolean ignorePermissions;

Expand All @@ -53,6 +54,11 @@ public class AssemblyConfiguration {
*/
private String user;

/**
* @parameter default-value="keep"
*/
private PermissionMode permissions;

public Boolean exportBasedir() {
return exportBasedir;
}
Expand Down Expand Up @@ -86,9 +92,17 @@ public AssemblyMode getMode() {
}

public Boolean isIgnorePermissions() {
// New permission mode has precedence
if (permissions != null) {
return permissions == PermissionMode.ignore;
}
return (ignorePermissions != null) ? ignorePermissions : Boolean.FALSE;
}


public PermissionMode getPermissions() {
return permissions != null ? permissions : PermissionMode.keep;
}

public static class Builder {

private final AssemblyConfiguration config = new AssemblyConfiguration();
Expand Down Expand Up @@ -128,11 +142,19 @@ public Builder exportBasedir(Boolean export) {
return this;
}

@Deprecated
public Builder ignorePermissions(Boolean ignorePermissions) {
config.ignorePermissions = set(ignorePermissions);
return this;
}

public Builder permissions(String permissions) {
if (permissions != null) {
config.permissions = PermissionMode.valueOf(permissions.toLowerCase());
}
return this;
}

public Builder user(String user) {
config.user = set(user);
return this;
Expand All @@ -153,4 +175,27 @@ private <T> T set(T prop) {
return prop;
}
}

public enum PermissionMode {

/**
* Auto detect permission mode
*/
auto,

/**
* Make everything executable
*/
exec,

/**
* Leave all as it is
*/
keep,

/**
* Ignore permission when using an assembly mode of "dir"
*/
ignore
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public enum ConfigKey {
ASSEMBLY_DESCRIPTOR_REF("assembly.descriptorRef"),
ASSEMBLY_EXPORT_BASEDIR("assembly.exportBaseDir"),
ASSEMBLY_IGNORE_PERMISSIONS("assembly.ignorePermissions"),
ASSEMBLY_PERMISSIONS("assembly.permissions"),
ASSEMBLY_DOCKER_FILE_DIR("assembly.dockerFileDir"),
ASSEMBLY_USER("assembly.user"),
ASSEMBLY_MODE("assembly.mode"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ private AssemblyConfiguration extractAssembly(String prefix, Properties properti
.dockerFileDir(withPrefix(prefix, ASSEMBLY_DOCKER_FILE_DIR, properties))
.exportBasedir(booleanWithPrefix(prefix, ASSEMBLY_EXPORT_BASEDIR, properties))
.ignorePermissions(booleanWithPrefix(prefix, ASSEMBLY_IGNORE_PERMISSIONS, properties))
.permissions(withPrefix(prefix, ASSEMBLY_PERMISSIONS, properties))
.user(withPrefix(prefix, ASSEMBLY_USER, properties))
.mode(withPrefix(prefix, ASSEMBLY_MODE, properties))
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,20 @@
* limitations under the License.
*/

import java.io.File;
import java.util.List;

import io.fabric8.maven.docker.assembly.AssemblyFiles;
import io.fabric8.maven.docker.assembly.DockerAssemblyManager;
import io.fabric8.maven.docker.config.BuildImageConfiguration;
import io.fabric8.maven.docker.config.ImageConfiguration;
import io.fabric8.maven.docker.util.Logger;
import io.fabric8.maven.docker.util.MojoParameters;
import io.fabric8.maven.docker.config.ImageConfiguration;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.assembly.InvalidAssemblerConfigurationException;
import org.apache.maven.plugin.assembly.archive.ArchiveCreationException;
import org.apache.maven.plugin.assembly.format.AssemblyFormattingException;

import java.io.File;
import java.util.List;

/**
* @author roland
* @since 30/11/15
Expand Down Expand Up @@ -56,7 +56,7 @@ public ArchiveService(DockerAssemblyManager dockerAssemblyManager,Logger log) {
*/
public File createDockerBuildArchive(ImageConfiguration imageConfig, MojoParameters params)
throws MojoExecutionException {
File ret = createArchive(imageConfig.getName(), imageConfig.getBuildConfiguration(), params);
File ret = createArchive(imageConfig.getName(), imageConfig.getBuildConfiguration(), params, log);
log.info("%s: Created docker source tar %s",imageConfig.getDescription(), ret);
return ret;
}
Expand Down Expand Up @@ -97,8 +97,8 @@ public File createChangedFilesArchive(List<AssemblyFiles.Entry> entries, File as

// =============================================

File createArchive(String imageName, BuildImageConfiguration buildConfig, MojoParameters params)
File createArchive(String imageName, BuildImageConfiguration buildConfig, MojoParameters params, Logger log)
throws MojoExecutionException {
return dockerAssemblyManager.createDockerTarArchive(imageName, params, buildConfig);
return dockerAssemblyManager.createDockerTarArchive(imageName, params, buildConfig, log);
}
}
Loading

0 comments on commit dcc7df6

Please sign in to comment.