Plugins: plugin script to set proper plugin config dir attributes
Depending on how elasticsearch is installed, we have two scenarios to take into account that relate to user, group and permissions assigned to the config directory: 1) deb/rpm package: /etc/elasticsearch is root:elasticsearch 750 and the plugin script is run from root user 2) tar/zip archive: es config dir is most likely elasticsearch:elasticsearch and the plugin script is most likely run from elasticsearch user When the plugin script copies over the plugin config dir within the es config dir, it should take care of setting the proper user, group and permissions, which vary depending on how elasticsearch was installed in the first place. Should be root:elasticsearch 750 if installed from a package, or elasticsearch:elasticsearch if installed from an archive. This commit makes sure that the plugin script looks at user, group and permissions of the config dir and copies them over to the plugin config subdirectory, whatever they are, so that they get properly setup depending on how elasticsearch was installed in the first place. We also make sure that execute permissions are left untouched for files. Relates to #11016 Closes #14048
This commit is contained in:
parent
1634c8364e
commit
4d7d29f65b
|
@ -36,9 +36,7 @@ import java.io.OutputStream;
|
|||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.PosixFileAttributeView;
|
||||
import java.nio.file.attribute.PosixFilePermission;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.StreamSupport;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
@ -255,7 +253,7 @@ public class PluginManager {
|
|||
copyBinDirectory(sourcePluginBinDirectory, destPluginBinDirectory, pluginHandle.name, terminal);
|
||||
} catch (IOException e) {
|
||||
// rollback and remove potentially before installed leftovers
|
||||
terminal.printError("Error copying bin directory [%s] to [%s], cleaning up, reason: %s", sourcePluginBinDirectory, destPluginBinDirectory, e.getMessage());
|
||||
terminal.printError("Error copying bin directory [%s] to [%s], cleaning up, reason: %s", sourcePluginBinDirectory, destPluginBinDirectory, ExceptionsHelper.detailedMessage(e));
|
||||
tryToDeletePath(terminal, extractLocation, pluginHandle.binDir(environment));
|
||||
throw e;
|
||||
}
|
||||
|
@ -274,15 +272,69 @@ public class PluginManager {
|
|||
try {
|
||||
terminal.println(VERBOSE, "Found config, moving to %s", destConfigDirectory.toAbsolutePath());
|
||||
moveFilesWithoutOverwriting(sourceConfigDirectory, destConfigDirectory, ".new");
|
||||
|
||||
if (Environment.getFileStore(destConfigDirectory).supportsFileAttributeView(PosixFileAttributeView.class)) {
|
||||
//We copy owner, group and permissions from the parent ES_CONFIG directory, assuming they were properly set depending
|
||||
// on how es was installed in the first place: can be root:elasticsearch (750) if es was installed from rpm/deb packages
|
||||
// or most likely elasticsearch:elasticsearch if installed from tar/zip. As for permissions we don't rely on umask.
|
||||
PosixFileAttributes parentDirAttributes = Files.getFileAttributeView(destConfigDirectory.getParent(), PosixFileAttributeView.class).readAttributes();
|
||||
//for files though, we make sure not to copy execute permissions from the parent dir and leave them untouched
|
||||
Set<PosixFilePermission> baseFilePermissions = new HashSet<>();
|
||||
for (PosixFilePermission posixFilePermission : parentDirAttributes.permissions()) {
|
||||
switch (posixFilePermission) {
|
||||
case OWNER_EXECUTE:
|
||||
case GROUP_EXECUTE:
|
||||
case OTHERS_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
baseFilePermissions.add(posixFilePermission);
|
||||
}
|
||||
}
|
||||
Files.walkFileTree(destConfigDirectory, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (attrs.isRegularFile()) {
|
||||
Set<PosixFilePermission> newFilePermissions = new HashSet<>(baseFilePermissions);
|
||||
Set<PosixFilePermission> currentFilePermissions = Files.getPosixFilePermissions(file);
|
||||
for (PosixFilePermission posixFilePermission : currentFilePermissions) {
|
||||
switch (posixFilePermission) {
|
||||
case OWNER_EXECUTE:
|
||||
case GROUP_EXECUTE:
|
||||
case OTHERS_EXECUTE:
|
||||
newFilePermissions.add(posixFilePermission);
|
||||
}
|
||||
}
|
||||
setPosixFileAttributes(file, parentDirAttributes.owner(), parentDirAttributes.group(), newFilePermissions);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
setPosixFileAttributes(dir, parentDirAttributes.owner(), parentDirAttributes.group(), parentDirAttributes.permissions());
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
terminal.println(VERBOSE, "Skipping posix permissions - filestore doesn't support posix permission");
|
||||
}
|
||||
|
||||
terminal.println(VERBOSE, "Installed %s into %s", pluginHandle.name, destConfigDirectory.toAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
terminal.printError("Error copying config directory [%s] to [%s], cleaning up, reason: %s", sourceConfigDirectory, destConfigDirectory, e.getMessage());
|
||||
terminal.printError("Error copying config directory [%s] to [%s], cleaning up, reason: %s", sourceConfigDirectory, destConfigDirectory, ExceptionsHelper.detailedMessage(e));
|
||||
tryToDeletePath(terminal, extractLocation, destPluginBinDirectory, destConfigDirectory);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setPosixFileAttributes(Path path, UserPrincipal owner, GroupPrincipal group, Set<PosixFilePermission> permissions) throws IOException {
|
||||
PosixFileAttributeView fileAttributeView = Files.getFileAttributeView(path, PosixFileAttributeView.class);
|
||||
fileAttributeView.setOwner(owner);
|
||||
fileAttributeView.setGroup(group);
|
||||
fileAttributeView.setPermissions(permissions);
|
||||
}
|
||||
|
||||
private void tryToDeletePath(Terminal terminal, Path ... paths) {
|
||||
for (Path path : paths) {
|
||||
try {
|
||||
|
|
|
@ -31,9 +31,13 @@ import org.junit.Before;
|
|||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.PosixFilePermissions;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.*;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
|
@ -250,6 +254,34 @@ public class PluginManagerPermissionTests extends ESTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public void testConfigDirectoryOwnerGroupAndPermissions() throws IOException {
|
||||
assumeTrue("File system does not support permissions, skipping", supportsPermissions);
|
||||
URL pluginUrl = createPlugin(false, true);
|
||||
PluginManager pluginManager = new PluginManager(environment, pluginUrl, PluginManager.OutputMode.VERBOSE, TimeValue.timeValueSeconds(10));
|
||||
pluginManager.downloadAndExtract(pluginName, terminal);
|
||||
PosixFileAttributes parentFileAttributes = Files.getFileAttributeView(environment.configFile(), PosixFileAttributeView.class).readAttributes();
|
||||
Path configPath = environment.configFile().resolve(pluginName);
|
||||
PosixFileAttributes pluginConfigDirAttributes = Files.getFileAttributeView(configPath, PosixFileAttributeView.class).readAttributes();
|
||||
assertThat(pluginConfigDirAttributes.owner(), equalTo(parentFileAttributes.owner()));
|
||||
assertThat(pluginConfigDirAttributes.group(), equalTo(parentFileAttributes.group()));
|
||||
assertThat(pluginConfigDirAttributes.permissions(), equalTo(parentFileAttributes.permissions()));
|
||||
Path configFile = configPath.resolve("my-custom-config.yaml");
|
||||
PosixFileAttributes pluginConfigFileAttributes = Files.getFileAttributeView(configFile, PosixFileAttributeView.class).readAttributes();
|
||||
assertThat(pluginConfigFileAttributes.owner(), equalTo(parentFileAttributes.owner()));
|
||||
assertThat(pluginConfigFileAttributes.group(), equalTo(parentFileAttributes.group()));
|
||||
Set<PosixFilePermission> expectedFilePermissions = new HashSet<>();
|
||||
for (PosixFilePermission parentPermission : parentFileAttributes.permissions()) {
|
||||
switch(parentPermission) {
|
||||
case OWNER_EXECUTE:
|
||||
case GROUP_EXECUTE:
|
||||
case OTHERS_EXECUTE:
|
||||
break;
|
||||
default:
|
||||
expectedFilePermissions.add(parentPermission);
|
||||
}
|
||||
}
|
||||
assertThat(pluginConfigFileAttributes.permissions(), equalTo(expectedFilePermissions));
|
||||
}
|
||||
|
||||
private URL createPlugin(boolean withBinDir, boolean withConfigDir) throws IOException {
|
||||
final Path structure = createTempDir().resolve("fake-plugin");
|
||||
|
|
|
@ -164,7 +164,7 @@ assert_file() {
|
|||
fi
|
||||
|
||||
if [ "x$user" != "x" ]; then
|
||||
realuser=$(ls -ld "$file" | awk '{print $3}')
|
||||
realuser=$(find "$file" -maxdepth 0 -printf "%u")
|
||||
[ "$realuser" = "$user" ]
|
||||
fi
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ remove_plugin() {
|
|||
fi
|
||||
}
|
||||
|
||||
# Install the jvm-example plugin which fully excercises the special case file
|
||||
# Install the jvm-example plugin which fully exercises the special case file
|
||||
# placements for non-site plugins.
|
||||
install_jvm_example() {
|
||||
local relativePath=${1:-$(readlink -m jvm-example-*.zip)}
|
||||
|
@ -81,14 +81,27 @@ install_jvm_example() {
|
|||
|
||||
assert_file_exist "$ESHOME/bin/jvm-example"
|
||||
assert_file_exist "$ESHOME/bin/jvm-example/test"
|
||||
assert_file_exist "$ESCONFIG/jvm-example"
|
||||
assert_file_exist "$ESCONFIG/jvm-example/example.yaml"
|
||||
|
||||
#owner group and permissions vary depending on how es was installed
|
||||
#just make sure that everything is the same as $CONFIG_DIR, which was properly set up during install
|
||||
config_user=$(find "$ESCONFIG" -maxdepth 0 -printf "%u")
|
||||
config_owner=$(find "$ESCONFIG" -maxdepth 0 -printf "%g")
|
||||
config_privileges=$(find "$ESCONFIG" -maxdepth 0 -printf "%m")
|
||||
assert_file "$ESCONFIG/jvm-example" d $config_user $config_owner $config_privileges
|
||||
#the original file has no execute permissions and that must not change, but all other permissions
|
||||
#need to be inherited from the parent config dir. We check this by applying the 111 mask to the config dir privileges.
|
||||
for i in `seq 0 2`; do
|
||||
current_perm_dir=${config_privileges:$i:1}
|
||||
final_perm=$(($current_perm_dir & ~1))
|
||||
expected_file_privileges+=$final_perm
|
||||
done
|
||||
assert_file "$ESCONFIG/jvm-example/example.yaml" f $config_user $config_owner $expected_file_privileges
|
||||
|
||||
echo "Running jvm-example's bin script...."
|
||||
"$ESHOME/bin/jvm-example/test" | grep test
|
||||
}
|
||||
|
||||
# Remove the jvm-example plugin which fully excercises the special cases of
|
||||
# Remove the jvm-example plugin which fully exercises the special cases of
|
||||
# removing bin and not removing config.
|
||||
remove_jvm_example() {
|
||||
remove_plugin jvm-example
|
||||
|
|
Loading…
Reference in New Issue