[java-identity-provider] 02/06: IDP-1595 Plugin Command line: List installed clients

Rod Widdowson rdw at steadingsoftware.com
Tue Aug 4 13:06:42 UTC 2020


This is an automated email from the git hooks/post-receive script.

rdw pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=851b4003cc251c491140c04660c4687e7579c680

commit 851b4003cc251c491140c04660c4687e7579c680
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Sun Aug 2 14:50:03 2020 +0100

    IDP-1595 Plugin Command line: List installed clients
    
    https://issues.shibboleth.net/jira/browse/IDP-1595
    
    -li/--list, -fl/--full-list
    
    Output is to System.out which has bizarre logging side effects.
---
 idp-installer/pom.xml                              |   7 ++
 .../installer/plugin/PluginInstallerArguments.java |  92 +++++++++++++++
 .../idp/installer/plugin/PluginInstallerCLI.java   | 127 ++++++++++++++++++---
 .../idp/installer/plugin/PluginCLITest.java        |   6 +-
 .../installer/plugin/impl/PluginInstallerTest.java |   3 +-
 .../net.shibboleth.idp.plugin.PluginDescription    |   1 +
 .../idphome-test/conf/admin/{gitkeep => .gitkeep}  |   0
 7 files changed, 213 insertions(+), 23 deletions(-)

diff --git a/idp-installer/pom.xml b/idp-installer/pom.xml
index cb0e5da29..d5073e131 100644
--- a/idp-installer/pom.xml
+++ b/idp-installer/pom.xml
@@ -159,6 +159,13 @@
             <artifactId>bcpkix-jdk15on</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>idp-admin-impl</artifactId>
+            <version>${project.version}</version>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
         
     </dependencies>
 
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerArguments.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerArguments.java
index 8c81e1e3b..41a07228f 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerArguments.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerArguments.java
@@ -17,6 +17,12 @@
 
 package net.shibboleth.idp.installer.plugin;
 
+import java.io.PrintStream;
+
+import javax.annotation.Nullable;
+
+import com.beust.jcommander.Parameter;
+
 import net.shibboleth.ext.spring.cli.AbstractCommandLineArguments;
 
 /**
@@ -24,4 +30,90 @@ import net.shibboleth.ext.spring.cli.AbstractCommandLineArguments;
  */
 public class PluginInstallerArguments extends AbstractCommandLineArguments {
 
+    /** The PluginId - usually used to drive the update. */
+    @Parameter(names= {"-p", "--pluginId"})
+    @Nullable private String pluginId;
+
+    /** Brief info about installed plugins. */
+    @Parameter(names= {"-l", "--list"})
+    @Nullable private boolean list;
+
+    /** Detailed info about installed plugins. */
+    @Parameter(names= {"-fl", "--full-list"})
+    @Nullable private boolean fullList;
+
+    /** Operation enum. */
+    public enum OperationType {
+        /** Update a known install. */
+        UPDATE,
+        /** List all installs. */
+        LIST,
+        /** Install from a local copy. */
+        INSTALLDIR,
+        /** Install from the web. */
+        INSTALLREMOTE,
+        /** Unknown. */
+        UNKNOWN
+    };
+
+    /** What to do. */
+    private OperationType operation = OperationType.UNKNOWN;
+
+    /** Plugin Id (if specified).
+     * @return {@link #pluginId}
+     */
+    @Nullable public String getPluginId() {
+        return pluginId;
+    }
+
+    /** Are we doing a full List?
+     * @return {@link #fullList}
+     */
+    public boolean getFullList() {
+        return fullList;
+    }
+
+    /** Are we doing a List?
+     * @return {@link #list}
+     */
+    public boolean getList() {
+        return list;
+    }
+
+    /**
+     * Get operation to perform.
+     *
+     * @return operation
+     */
+    @Nullable public OperationType getOperation() {
+        return operation;
+    }
+
+    /** {@inheritDoc} */
+    public void validate() throws IllegalArgumentException {
+        super.validate();
+
+        if (getOtherArgs().size() > 2) {
+            throw new IllegalArgumentException("????");
+        }
+        if (list || fullList) {
+            operation = OperationType.LIST;
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void printHelp(final PrintStream out) {
+        out.println("Plugin");
+        out.println("Provides a command line interface for plugin management operations.");
+        out.println();
+        out.println("   Plugn [options] springConfiguration [FullName]");
+        out.println();
+        out.println("      springConfiguration      name of Spring configuration resource to use");
+        super.printHelp(out);
+        out.println();
+        out.println(String.format("  %-22s %s", "-l, --list", "Brief Information of all installed plugins"));
+        out.println(String.format("  %-22s %s", "-fl, --full-list", "Full details of all installed plugins"));
+        out.println();
+    }
+
 }
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerCLI.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerCLI.java
index 3e944b1e7..5f1e50fd8 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerCLI.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/PluginInstallerCLI.java
@@ -17,25 +17,32 @@
 
 package net.shibboleth.idp.installer.plugin;
 
-import java.io.IOException;
-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.BasicFileAttributes;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.apache.http.client.HttpClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.core.io.FileSystemResource;
 import org.springframework.core.io.Resource;
 
 import net.shibboleth.ext.spring.cli.AbstractCommandLine;
 import net.shibboleth.idp.Version;
+import net.shibboleth.idp.installer.plugin.impl.PluginInstaller;
+import net.shibboleth.idp.plugin.PluginDescription;
+import net.shibboleth.idp.plugin.PluginVersion;
+import net.shibboleth.idp.plugin.impl.PluginState;
+import net.shibboleth.idp.plugin.impl.PluginState.VersionInfo;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /**
@@ -48,7 +55,13 @@ public final class PluginInstallerCLI extends AbstractCommandLine<PluginInstalle
     
     /** Where the IdP is installed to. */
     @Nullable private Path idpHome;
+
+    /** A Plugin Installer to use. */
+    private PluginInstaller installer;
     
+    /** The injected HttpClient. */
+    private HttpClient httpClient;
+
     /**
      * Constrained Constructor.
      */
@@ -113,27 +126,103 @@ public final class PluginInstallerCLI extends AbstractCommandLine<PluginInstalle
         if (ret != RC_OK) {
             return ret;
         }
+        final Set<Entry<String, HttpClient>> clients =
+                getApplicationContext().getBeansOfType(HttpClient.class).entrySet();
+        if (clients.isEmpty()) {
+            log.debug("No HttpClient definitions found.");
+        } else {
+            final Entry<String, HttpClient> entry = clients.iterator().next();
+            httpClient = entry.getValue();
+            if (clients.size() > 1) {
+                log.warn("Multiple HttpClient beans found; Taking {}", entry.getKey());
+            } else {
+                log.debug("Selecting HttpClient: {}", entry.getKey());
+            }
+        }
+
         try {
-            Files.walkFileTree(getIdpHome().resolve("conf"), new SimpleFileVisitor<Path>() {
-                @Override 
-                public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
-                    getLogger().warn("File {}",file);
-                    return FileVisitResult.CONTINUE;
-                }
-                @Override 
-                public FileVisitResult preVisitDirectory(final Path dir,
-                        final BasicFileAttributes attrs) throws IOException {
-                    getLogger().warn("Dire {}",dir);
-                    return FileVisitResult.CONTINUE;
-                }
-            });
-        } catch (final IOException e) {
-            getLogger().error("oops", e);
+            constructPluginInstaller();
+            switch (args.getOperation()) {
+                case LIST:
+                    doList(args.getFullList(), args.getPluginId());
+                    break;
+
+                default:
+                    getLogger().error("Invalid operation");
+                    return RC_IO;
+            }
+
+        } catch (final ComponentInitializationException | BeansException e) {
+            getLogger().error("Plugin failed", e);
             return RC_IO;
         } 
         return ret;
     }
 
+    /** Build the installer.
+     * @throws ComponentInitializationException as required*/
+    private void constructPluginInstaller() throws ComponentInitializationException {
+        installer= new PluginInstaller();
+        installer.setIdpHome(idpHome);
+        if (httpClient!= null) {
+            installer.setHttpClient(httpClient);
+        }
+        installer.initialize();
+    }
+
+    /** List all installed plugins (or just one if provided).
+     * @param fullList whether to do full deatils
+     * @param pluginId the pluginId or null.
+     */
+    private void doList(final boolean fullList, @Nullable final String pluginId) {
+        boolean list = false;
+        final List<PluginDescription> plugins = installer.getInstalledPlugins();
+        for (final PluginDescription plugin: plugins) {
+            if (pluginId == null || pluginId.equals(plugin.getPluginId())) {
+                list = true;
+                System.out.println(String.format("Plugin: %-22s\tCurrent Version: %d.%d.%d",
+                       plugin.getPluginId(),
+                       plugin.getMajorVersion(),plugin.getMinorVersion(), plugin.getPatchVersion()));
+                if (fullList) {
+                    printDetails(plugin);
+                }
+            }
+        }
+        if (!list) {
+            if (pluginId == null) {
+                System.out.println("No plugins installed");
+            } else {
+                System.out.println("Plugin " + pluginId + " not installed");
+            }
+        }
+    }
+
+    /** Print our more information about a plugin.
+     * @param plugin what we are interested in.
+     */
+    private void printDetails(final PluginDescription plugin) {
+        log.debug("Interrogating {} ", plugin.getPluginId());
+        final PluginState state =  new PluginState(plugin);
+        if (httpClient != null) {
+            state.setHttpClient(httpClient);
+        }
+        try {
+            state.initialize();
+        } catch (final ComponentInitializationException e) {
+            log.error("Could not interrogate plugin {}", plugin.getPluginId(), e);
+            return;
+        }
+        final Map<PluginVersion, VersionInfo> versions = state.getAvailableVersions();
+        System.out.println("\tVersions ");
+        for (final Entry<PluginVersion, VersionInfo> entry  : versions.entrySet()) {
+            System.out.println(String.format("\t%s:\tMin=%s\tMax=%s\tSupport level: %s",
+                    entry.getKey(),
+                    entry.getValue().getMinSupported(),
+                    entry.getValue().getMaxSupported(),
+                    entry.getValue().getSupportLevel()));
+        }
+    }
+
     /** Shim for CLI entry point: Allows the code to be run from a test.
      *
      * @return one of the predefines {@link AbstractCommandLine#RC_INIT},
diff --git a/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/PluginCLITest.java b/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/PluginCLITest.java
index 1f567f3ab..f2d87ff99 100644
--- a/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/PluginCLITest.java
+++ b/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/PluginCLITest.java
@@ -34,7 +34,7 @@ import net.shibboleth.ext.spring.cli.AbstractCommandLine;
 @SuppressWarnings("javadoc")
 public class PluginCLITest extends BasePluginTest {
     
-    @Test(enabled = true) public void TestCli() throws IOException {
+    @Test(enabled = true) public void testList() throws IOException {
         System.setProperty("net.shibboleth.idp.cli.idp.home",getIdpHome().toString());
         final Resource pluginInstaller = new ClassPathResource("conf/admin/plugin-installer.xml");
         final File plugin = getIdpHome().resolve("conf").resolve("admin").resolve("plugin-installer.xml").toFile();
@@ -45,7 +45,7 @@ public class PluginCLITest extends BasePluginTest {
             is.transferTo(os);
         }
     
-        assertEquals(PluginInstallerCLI.runMain(new String[] { plugin.getAbsolutePath(), "--verbose"}), 
-                AbstractCommandLine.RC_OK);	
+        assertEquals(PluginInstallerCLI.runMain(new String[] { plugin.getAbsolutePath(), "-fl"}),
+                AbstractCommandLine.RC_OK);
     }
 }
diff --git a/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java b/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java
index c6f5ca425..ae087f472 100644
--- a/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java
+++ b/idp-installer/src/test/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerTest.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.net.URL;
 import java.nio.file.Path;
 import java.security.Security;
+import java.util.Collections;
 import java.util.List;
 import java.util.function.Predicate;
 
@@ -119,7 +120,7 @@ public class PluginInstallerTest extends BasePluginTest {
 
         /** {@inheritDoc} */
         public List<URL> getUpdateURLs() throws IOException {
-            return null;
+            return Collections.emptyList();
         }
 
         /** {@inheritDoc} */
diff --git a/idp-installer/src/test/resources/META-INF/services/net.shibboleth.idp.plugin.PluginDescription b/idp-installer/src/test/resources/META-INF/services/net.shibboleth.idp.plugin.PluginDescription
new file mode 100644
index 000000000..abc52d47f
--- /dev/null
+++ b/idp-installer/src/test/resources/META-INF/services/net.shibboleth.idp.plugin.PluginDescription
@@ -0,0 +1 @@
+net.shibboleth.idp.plugin.TestPlugin
diff --git a/idp-installer/src/test/resources/idphome-test/conf/admin/gitkeep b/idp-installer/src/test/resources/idphome-test/conf/admin/.gitkeep
similarity index 100%
rename from idp-installer/src/test/resources/idphome-test/conf/admin/gitkeep
rename to idp-installer/src/test/resources/idphome-test/conf/admin/.gitkeep

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list