3030import org .elasticsearch .cli .ExitCodes ;
3131import org .elasticsearch .cli .Terminal ;
3232import org .elasticsearch .cli .UserException ;
33+ import org .elasticsearch .common .Strings ;
3334import org .elasticsearch .common .SuppressForbidden ;
3435import org .elasticsearch .common .collect .Tuple ;
3536import org .elasticsearch .common .hash .MessageDigests ;
7576import java .util .zip .ZipInputStream ;
7677
7778import static org .elasticsearch .cli .Terminal .Verbosity .VERBOSE ;
78- import static org .elasticsearch .plugins .MetaPluginInfo .ES_META_PLUGIN_PROPERTIES ;
7979
8080/**
8181 * A command for the plugin cli to install a plugin into elasticsearch.
@@ -626,8 +626,7 @@ private void install(Terminal terminal, boolean isBatch, Path tmpRoot, Environme
626626 if (MetaPluginInfo .isMetaPlugin (tmpRoot )) {
627627 installMetaPlugin (terminal , isBatch , tmpRoot , env , deleteOnFailure );
628628 } else {
629- installPlugin (terminal , isBatch , tmpRoot , env .pluginsFile (), env .binFile (),
630- env .configFile (), env , deleteOnFailure );
629+ installPlugin (terminal , isBatch , tmpRoot , env , deleteOnFailure );
631630 }
632631 } catch (Exception installProblem ) {
633632 try {
@@ -639,55 +638,65 @@ private void install(Terminal terminal, boolean isBatch, Path tmpRoot, Environme
639638 }
640639 }
641640
642-
643641 /**
644- * Installs all plugins bundled in the meta plugin into the plugins dir (under the meta plugin directory).
642+ * Installs the meta plugin and all the bundled plugins from {@code tmpRoot} into the plugins dir.
643+ * If a bundled plugin has a bin dir and/or a config dir, those are copied.
645644 */
646645 private void installMetaPlugin (Terminal terminal , boolean isBatch , Path tmpRoot ,
647646 Environment env , List <Path > deleteOnFailure ) throws Exception {
648647 final MetaPluginInfo metaInfo = MetaPluginInfo .readFromProperties (tmpRoot );
649648 verifyPluginName (env .pluginsFile (), metaInfo .getName (), tmpRoot );
650- final Path metaPath = env .pluginsFile ().resolve (metaInfo .getName ());
649+ final Path destination = env .pluginsFile ().resolve (metaInfo .getName ());
650+ deleteOnFailure .add (destination );
651651 terminal .println (VERBOSE , metaInfo .toString ());
652-
653- // creates the meta plugin directory where all plugins are copied
654- Files .createDirectory (metaPath );
655- deleteOnFailure .add (metaPath );
656- setFileAttributes (metaPath , PLUGIN_DIR_PERMS );
657-
658- // copy the meta plugin properties file in the meta plugin directory
659- Path metaInfoDest = metaPath .resolve (ES_META_PLUGIN_PROPERTIES );
660- Files .copy (tmpRoot .resolve (ES_META_PLUGIN_PROPERTIES ), metaInfoDest );
661- setFileAttributes (metaInfoDest , PLUGIN_FILES_PERMS );
662-
663- // install all plugins
652+ final List <PluginInfo > pluginInfos = new ArrayList <>();
664653 try (DirectoryStream <Path > subPaths = Files .newDirectoryStream (tmpRoot )) {
665654 for (Path subPlugin : subPaths ) {
666655 if (MetaPluginInfo .isPropertiesFile (subPlugin )) {
667656 continue ;
668657 }
669- installPlugin (terminal , isBatch , subPlugin , env .pluginsFile ().resolve (metaInfo .getName ()),
670- env .binFile ().resolve (metaInfo .getName ()), env .configFile ().resolve (metaInfo .getName ()), env , deleteOnFailure );
658+ final PluginInfo info = verify (terminal , subPlugin , isBatch , env );
659+ pluginInfos .add (info );
660+ Path tmpBinDir = subPlugin .resolve ("bin" );
661+ if (Files .exists (tmpBinDir )) {
662+ Path destBinDir = env .binFile ().resolve (metaInfo .getName ()).resolve (info .getName ());
663+ deleteOnFailure .add (destBinDir );
664+ installBin (info , tmpBinDir , destBinDir );
665+ }
666+
667+ Path tmpConfigDir = subPlugin .resolve ("config" );
668+ if (Files .exists (tmpConfigDir )) {
669+ // some files may already exist, and we don't remove plugin config files on plugin removal,
670+ // so any installed config files are left on failure too
671+ Path destConfigDir = env .configFile ().resolve (metaInfo .getName ()).resolve (info .getName ());
672+ installConfig (info , tmpConfigDir , destConfigDir );
673+ }
671674 }
672675 }
673- // clean up installation
674- IOUtils .rm (tmpRoot );
675- terminal .println ("-> Installed " + metaInfo .getName ());
676+ movePlugin (tmpRoot , destination );
677+ for (PluginInfo info : pluginInfos ) {
678+ if (info .requiresKeystore ()) {
679+ createKeystoreIfNeeded (terminal , env , info );
680+ break ;
681+ }
682+ }
683+ String [] plugins = pluginInfos .stream ().map (PluginInfo ::getName ).toArray (String []::new );
684+ terminal .println ("-> Installed " + metaInfo .getName () + " with: " + Strings .arrayToCommaDelimitedString (plugins ));
676685 }
677686
678687 /**
679688 * Installs the plugin from {@code tmpRoot} into the plugins dir.
680689 * If the plugin has a bin dir and/or a config dir, those are copied.
681690 */
682- private void installPlugin (Terminal terminal , boolean isBatch , Path tmpRoot , Path pluginsDir , Path binDir , Path configDir ,
691+ private void installPlugin (Terminal terminal , boolean isBatch , Path tmpRoot ,
683692 Environment env , List <Path > deleteOnFailure ) throws Exception {
684693 final PluginInfo info = verify (terminal , tmpRoot , isBatch , env );
685- final Path destination = pluginsDir .resolve (info .getName ());
694+ final Path destination = env . pluginsFile () .resolve (info .getName ());
686695 deleteOnFailure .add (destination );
687696
688697 Path tmpBinDir = tmpRoot .resolve ("bin" );
689698 if (Files .exists (tmpBinDir )) {
690- Path destBinDir = binDir .resolve (info .getName ());
699+ Path destBinDir = env . binFile () .resolve (info .getName ());
691700 deleteOnFailure .add (destBinDir );
692701 installBin (info , tmpBinDir , destBinDir );
693702 }
@@ -696,10 +705,18 @@ private void installPlugin(Terminal terminal, boolean isBatch, Path tmpRoot, Pat
696705 if (Files .exists (tmpConfigDir )) {
697706 // some files may already exist, and we don't remove plugin config files on plugin removal,
698707 // so any installed config files are left on failure too
699- Path destConfigDir = configDir .resolve (info .getName ());
708+ Path destConfigDir = env . configFile () .resolve (info .getName ());
700709 installConfig (info , tmpConfigDir , destConfigDir );
701710 }
711+ movePlugin (tmpRoot , destination );
712+ if (info .requiresKeystore ()) {
713+ createKeystoreIfNeeded (terminal , env , info );
714+ }
715+ terminal .println ("-> Installed " + info .getName ());
716+ }
702717
718+ /** Moves the plugin directory into its final destination. **/
719+ private void movePlugin (Path tmpRoot , Path destination ) throws IOException {
703720 Files .move (tmpRoot , destination , StandardCopyOption .ATOMIC_MOVE );
704721 Files .walkFileTree (destination , new SimpleFileVisitor <Path >() {
705722 @ Override
@@ -718,15 +735,6 @@ public FileVisitResult postVisitDirectory(final Path dir, final IOException exc)
718735 return FileVisitResult .CONTINUE ;
719736 }
720737 });
721- if (info .requiresKeystore ()) {
722- KeyStoreWrapper keystore = KeyStoreWrapper .load (env .configFile ());
723- if (keystore == null ) {
724- terminal .println ("Elasticsearch keystore is required by plugin [" + info .getName () + "], creating..." );
725- keystore = KeyStoreWrapper .create (new char [0 ]);
726- keystore .save (env .configFile ());
727- }
728- }
729- terminal .println ("-> Installed " + info .getName ());
730738 }
731739
732740
@@ -793,6 +801,15 @@ private void installConfig(PluginInfo info, Path tmpConfigDir, Path destConfigDi
793801 IOUtils .rm (tmpConfigDir ); // clean up what we just copied
794802 }
795803
804+ private void createKeystoreIfNeeded (Terminal terminal , Environment env , PluginInfo info ) throws Exception {
805+ KeyStoreWrapper keystore = KeyStoreWrapper .load (env .configFile ());
806+ if (keystore == null ) {
807+ terminal .println ("Elasticsearch keystore is required by plugin [" + info .getName () + "], creating..." );
808+ keystore = KeyStoreWrapper .create (new char [0 ]);
809+ keystore .save (env .configFile ());
810+ }
811+ }
812+
796813 private static void setOwnerGroup (final Path path , final PosixFileAttributes attributes ) throws IOException {
797814 Objects .requireNonNull (attributes );
798815 PosixFileAttributeView fileAttributeView = Files .getFileAttributeView (path , PosixFileAttributeView .class );
0 commit comments