@Test
  public void testLocalPluginInstallWithBinAndConfig() throws Exception {
    String pluginName = "plugin-test";
    Tuple<Settings, Environment> initialSettings =
        InternalSettingsPreparer.prepareSettings(
            ImmutableSettings.settingsBuilder().build(), false);
    Environment env = initialSettings.v2();
    Path binDir = env.homeFile().resolve("bin");
    if (!Files.exists(binDir)) {
      Files.createDirectories(binDir);
    }
    Path pluginBinDir = binDir.resolve(pluginName);
    Path configDir = env.configFile();
    if (!Files.exists(configDir)) {
      Files.createDirectories(configDir);
    }
    Path pluginConfigDir = configDir.resolve(pluginName);
    try {

      PluginManager pluginManager =
          pluginManager(getPluginUrlForResource("plugin_with_bin_and_config.zip"), initialSettings);

      pluginManager.downloadAndExtract(pluginName);

      Path[] plugins = pluginManager.getListInstalledPlugins();

      assertThat(plugins, arrayWithSize(1));
      assertDirectoryExists(pluginBinDir);
      assertDirectoryExists(pluginConfigDir);
      Path toolFile = pluginBinDir.resolve("tool");
      assertFileExists(toolFile);

      // check that the file is marked executable, without actually checking that we can execute it.
      PosixFileAttributeView view =
          Files.getFileAttributeView(toolFile, PosixFileAttributeView.class);
      // the view might be null, on e.g. windows, there is nothing to check there!
      if (view != null) {
        PosixFileAttributes attributes = view.readAttributes();
        assertTrue(
            "unexpected permissions: " + attributes.permissions(),
            attributes.permissions().contains(PosixFilePermission.OWNER_EXECUTE));
      }
    } finally {
      // we need to clean up the copied dirs
      IOUtils.rm(pluginBinDir, pluginConfigDir);
    }
  }
예제 #2
0
  public FileAttrs getAttrs() throws IOException {
    FileAttrs result;
    BasicFileAttributes attr;
    DosFileAttributes dosAttr;
    PosixFileAttributes posixAttr;

    result = new FileAttrs();
    attr = Files.readAttributes(this.path.toPath(), BasicFileAttributes.class);

    result.setCtime(attr.creationTime().toMillis());
    result.setMtime(attr.lastModifiedTime().toMillis());
    // result.append("symlink", attr.isSymbolicLink()); //Redundant
    result.setSize(attr.size());

    if (System.getProperty("os.name").startsWith("Windows")) {
      dosAttr = Files.readAttributes(this.path.toPath(), DosFileAttributes.class);

      result.setDosArchive(dosAttr.isArchive());
      result.setDosHidden(dosAttr.isHidden());
      result.setDosReadonly(dosAttr.isReadOnly());
      result.setDosSystem(dosAttr.isSystem());
    } else {
      posixAttr = Files.readAttributes(this.path.toPath(), PosixFileAttributes.class);

      result.setPosixSymlink(this.isSymlink());

      if (result.getPosixSymlink()) {
        result.setLinkTo(Files.readSymbolicLink(this.path.toPath()).toString());
      }

      result.setPosixOwner(posixAttr.owner().getName());
      result.setPosixGroup(posixAttr.group().getName());
      result.setPosixPermission(PosixFilePermissions.toString(posixAttr.permissions()));
    }

    return result;
  }
예제 #3
0
  private void copyBinDirectory(
      Path sourcePluginBinDirectory,
      Path destPluginBinDirectory,
      String pluginName,
      Terminal terminal)
      throws IOException {
    boolean canCopyFromSource =
        Files.exists(sourcePluginBinDirectory)
            && Files.isReadable(sourcePluginBinDirectory)
            && Files.isDirectory(sourcePluginBinDirectory);
    if (canCopyFromSource) {
      terminal.println(VERBOSE, "Found bin, moving to %s", destPluginBinDirectory.toAbsolutePath());
      if (Files.exists(destPluginBinDirectory)) {
        IOUtils.rm(destPluginBinDirectory);
      }
      try {
        Files.createDirectories(destPluginBinDirectory.getParent());
        FileSystemUtils.move(sourcePluginBinDirectory, destPluginBinDirectory);
      } catch (IOException e) {
        throw new IOException(
            "Could not move [" + sourcePluginBinDirectory + "] to [" + destPluginBinDirectory + "]",
            e);
      }
      if (Environment.getFileStore(destPluginBinDirectory)
          .supportsFileAttributeView(PosixFileAttributeView.class)) {
        final PosixFileAttributes parentDirAttributes =
            Files.getFileAttributeView(
                    destPluginBinDirectory.getParent(), PosixFileAttributeView.class)
                .readAttributes();
        // copy permissions from parent bin directory
        final Set<PosixFilePermission> filePermissions = new HashSet<>();
        for (PosixFilePermission posixFilePermission : parentDirAttributes.permissions()) {
          switch (posixFilePermission) {
            case OWNER_EXECUTE:
            case GROUP_EXECUTE:
            case OTHERS_EXECUTE:
              break;
            default:
              filePermissions.add(posixFilePermission);
          }
        }
        // add file execute permissions to existing perms, so execution will work.
        filePermissions.add(PosixFilePermission.OWNER_EXECUTE);
        filePermissions.add(PosixFilePermission.GROUP_EXECUTE);
        filePermissions.add(PosixFilePermission.OTHERS_EXECUTE);
        Files.walkFileTree(
            destPluginBinDirectory,
            new SimpleFileVisitor<Path>() {
              @Override
              public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                  throws IOException {
                if (attrs.isRegularFile()) {
                  setPosixFileAttributes(
                      file,
                      parentDirAttributes.owner(),
                      parentDirAttributes.group(),
                      filePermissions);
                }
                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", pluginName, destPluginBinDirectory.toAbsolutePath());
    }
  }
예제 #4
0
  private void extract(PluginHandle pluginHandle, Terminal terminal, Path pluginFile)
      throws IOException {
    // unzip plugin to a staging temp dir, named for the plugin
    Path tmp = Files.createTempDirectory(environment.tmpFile(), null);
    Path root = tmp.resolve(pluginHandle.name);
    unzipPlugin(pluginFile, root);

    // find the actual root (in case its unzipped with extra directory wrapping)
    root = findPluginRoot(root);

    // read and validate the plugin descriptor
    PluginInfo info = PluginInfo.readFromProperties(root);
    terminal.println(VERBOSE, "%s", info);

    // update name in handle based on 'name' property found in descriptor file
    pluginHandle = new PluginHandle(info.getName(), pluginHandle.version, pluginHandle.user);
    final Path extractLocation = pluginHandle.extractedDir(environment);
    if (Files.exists(extractLocation)) {
      throw new IOException(
          "plugin directory "
              + extractLocation.toAbsolutePath()
              + " already exists. To update the plugin, uninstall it first using 'remove "
              + pluginHandle.name
              + "' command");
    }

    // check for jar hell before any copying
    if (info.isJvm()) {
      jarHellCheck(root, info.isIsolated());
    }

    // install plugin
    FileSystemUtils.copyDirectoryRecursively(root, extractLocation);
    terminal.println("Installed %s into %s", pluginHandle.name, extractLocation.toAbsolutePath());

    // cleanup
    tryToDeletePath(terminal, tmp, pluginFile);

    // take care of bin/ by moving and applying permissions if needed
    Path sourcePluginBinDirectory = extractLocation.resolve("bin");
    Path destPluginBinDirectory = pluginHandle.binDir(environment);
    boolean needToCopyBinDirectory = Files.exists(sourcePluginBinDirectory);
    if (needToCopyBinDirectory) {
      if (Files.exists(destPluginBinDirectory) && !Files.isDirectory(destPluginBinDirectory)) {
        tryToDeletePath(terminal, extractLocation);
        throw new IOException(
            "plugin bin directory " + destPluginBinDirectory + " is not a directory");
      }

      try {
        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, ExceptionsHelper.detailedMessage(e));
        tryToDeletePath(terminal, extractLocation, pluginHandle.binDir(environment));
        throw e;
      }
    }

    Path sourceConfigDirectory = extractLocation.resolve("config");
    Path destConfigDirectory = pluginHandle.configDir(environment);
    boolean needToCopyConfigDirectory = Files.exists(sourceConfigDirectory);
    if (needToCopyConfigDirectory) {
      if (Files.exists(destConfigDirectory) && !Files.isDirectory(destConfigDirectory)) {
        tryToDeletePath(terminal, extractLocation, destPluginBinDirectory);
        throw new IOException(
            "plugin config directory " + destConfigDirectory + " is not a directory");
      }

      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.
          final 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
          final 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, ExceptionsHelper.detailedMessage(e));
        tryToDeletePath(terminal, extractLocation, destPluginBinDirectory, destConfigDirectory);
        throw e;
      }
    }
  }
예제 #5
0
 static void checkPosixAttributes(PosixFileAttributes attrs1, PosixFileAttributes attrs2) {
   assertTrue(attrs1.permissions().equals(attrs2.permissions()));
   assertTrue(attrs1.owner().equals(attrs2.owner()));
   assertTrue(attrs1.group().equals(attrs2.group()));
 }
 /**
  * Invoked by readAttributes or sub-classes to add all matching posix attributes to the builder
  */
 final void addRequestedPosixAttributes(PosixFileAttributes attrs, AttributesBuilder builder) {
   addRequestedBasicAttributes(attrs, builder);
   if (builder.match(PERMISSIONS_NAME)) builder.add(PERMISSIONS_NAME, attrs.permissions());
   if (builder.match(OWNER_NAME)) builder.add(OWNER_NAME, attrs.owner());
   if (builder.match(GROUP_NAME)) builder.add(GROUP_NAME, attrs.group());
 }
  void assertPlugin(String name, Path original, Environment env) throws IOException {
    Path got = env.pluginsFile().resolve(name);
    assertTrue("dir " + name + " exists", Files.exists(got));

    if (isPosix) {
      Set<PosixFilePermission> perms = Files.getPosixFilePermissions(got);
      assertThat(
          perms,
          containsInAnyOrder(
              PosixFilePermission.OWNER_READ,
              PosixFilePermission.OWNER_WRITE,
              PosixFilePermission.OWNER_EXECUTE,
              PosixFilePermission.GROUP_READ,
              PosixFilePermission.GROUP_EXECUTE,
              PosixFilePermission.OTHERS_READ,
              PosixFilePermission.OTHERS_EXECUTE));
    }

    assertTrue("jar was copied", Files.exists(got.resolve("plugin.jar")));
    assertFalse("bin was not copied", Files.exists(got.resolve("bin")));
    assertFalse("config was not copied", Files.exists(got.resolve("config")));
    if (Files.exists(original.resolve("bin"))) {
      Path binDir = env.binFile().resolve(name);
      assertTrue("bin dir exists", Files.exists(binDir));
      assertTrue("bin is a dir", Files.isDirectory(binDir));
      PosixFileAttributes binAttributes = null;
      if (isPosix) {
        binAttributes = Files.readAttributes(env.binFile(), PosixFileAttributes.class);
      }
      try (DirectoryStream<Path> stream = Files.newDirectoryStream(binDir)) {
        for (Path file : stream) {
          assertFalse("not a dir", Files.isDirectory(file));
          if (isPosix) {
            PosixFileAttributes attributes = Files.readAttributes(file, PosixFileAttributes.class);
            assertEquals(InstallPluginCommand.BIN_FILES_PERMS, attributes.permissions());
          }
        }
      }
    }
    if (Files.exists(original.resolve("config"))) {
      Path configDir = env.configFile().resolve(name);
      assertTrue("config dir exists", Files.exists(configDir));
      assertTrue("config is a dir", Files.isDirectory(configDir));

      UserPrincipal user = null;
      GroupPrincipal group = null;

      if (isPosix) {
        PosixFileAttributes configAttributes =
            Files.getFileAttributeView(env.configFile(), PosixFileAttributeView.class)
                .readAttributes();
        user = configAttributes.owner();
        group = configAttributes.group();

        PosixFileAttributes attributes =
            Files.getFileAttributeView(configDir, PosixFileAttributeView.class).readAttributes();
        assertThat(attributes.owner(), equalTo(user));
        assertThat(attributes.group(), equalTo(group));
      }

      try (DirectoryStream<Path> stream = Files.newDirectoryStream(configDir)) {
        for (Path file : stream) {
          assertFalse("not a dir", Files.isDirectory(file));

          if (isPosix) {
            PosixFileAttributes attributes = Files.readAttributes(file, PosixFileAttributes.class);
            if (user != null) {
              assertThat(attributes.owner(), equalTo(user));
            }
            if (group != null) {
              assertThat(attributes.group(), equalTo(group));
            }
          }
        }
      }
    }
    assertInstallCleaned(env);
  }