[java-identity-provider] 02/02: IDP-1595 Add Update to the plugin installer.

Rod Widdowson rdw at steadingsoftware.com
Tue Sep 1 15:31:54 UTC 2020


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

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

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

commit 3bd68ccf10b102790e315c634549a16509852e49
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Tue Sep 1 16:30:35 2020 +0100

    IDP-1595 Add Update to the plugin installer.
    
    https://issues.shibboleth.net/jira/browse/IDP-1595
    
    Automatically finds the best version to install.  An extra
    qualifier is supplied to allow overriding of the version with
    no checks.
---
 .../shibboleth/idp/plugin/impl/PluginState.java    |  5 +-
 .../installer/plugin/PluginInstallerArguments.java | 73 ++++++++++++++--
 .../idp/installer/plugin/PluginInstallerCLI.java   | 97 ++++++++++++++++++++++
 .../idp/installer/plugin/PluginCLITest.java        | 35 ++++----
 4 files changed, 187 insertions(+), 23 deletions(-)

diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/plugin/impl/PluginState.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/plugin/impl/PluginState.java
index 6ff60cf33..d3c2fa228 100644
--- a/idp-admin-impl/src/main/java/net/shibboleth/idp/plugin/impl/PluginState.java
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/plugin/impl/PluginState.java
@@ -176,12 +176,15 @@ public class PluginState extends AbstractInitializableComponent {
         if (myPluginVersion.equals(theVersion)) {
             myVersionInfo = info;
         }
-        final String downloadURL =  StringSupport.trimOrNull(
+        String downloadURL =  StringSupport.trimOrNull(
                 props.getProperty(plugin.getPluginId() + PluginSupport.DOWNLOAD_URL_INTERFIX + version));
         final String baseName =  StringSupport.trimOrNull(
                 props.getProperty(plugin.getPluginId() + PluginSupport.BASE_NAME_INTERFIX + version));
         if (baseName != null && downloadURL != null) {
             try {
+                if (!downloadURL.endsWith("/")) {
+                    downloadURL += "/";
+                }
                 final URL url = new URL(downloadURL);
                 downloadInfo.put(theVersion, new Pair<>(url, baseName));
                 log.trace("Plugin {}, version {} : Added download URL {}  baseName {} for {}",
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 732d2d659..c08ff7e47 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
@@ -22,6 +22,7 @@ import java.io.PrintStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.nio.file.Path;
+import java.util.List;
 
 import javax.annotation.Nullable;
 
@@ -31,6 +32,7 @@ import org.slf4j.LoggerFactory;
 import com.beust.jcommander.Parameter;
 
 import net.shibboleth.ext.spring.cli.AbstractCommandLineArguments;
+import net.shibboleth.idp.plugin.PluginVersion;
 
 /**
  * Arguments for Plugin Installer CLI.
@@ -56,6 +58,17 @@ public class PluginInstallerArguments extends AbstractCommandLineArguments {
     @Parameter(names= {"-i", "--input"})
     @Nullable private String input;
 
+    /** Update plugin Id. */
+    @Parameter(names= {"-u", "--update"})
+    @Nullable private String updatePluginId;
+
+    /** Force update version. */
+    @Parameter(names= {"-fu", "--force-update"})
+    @Nullable private String forceUpdateVersion;
+
+    /** The {@link #forceUpdateVersion} as a {@link PluginVersion}. */
+    @Nullable private PluginVersion updateVersion;
+
     /** Decomposed input - name. */
     @Nullable private String inputName;
 
@@ -91,12 +104,18 @@ public class PluginInstallerArguments extends AbstractCommandLineArguments {
 
     /** Get the digested parent URL.
      * @return Returns the digested parent URL.
+     *
+     * Only valid for {@link OperationType#INSTALLREMOTE}.
      */
     public URL getInputURL() {
         return inputURL;
     }
 
     /** Get the file Name.
+     *
+     * Only valid for {@link OperationType#INSTALLDIR}
+     * and {@link OperationType#INSTALLREMOTE}.
+     *
      * @return Returns the digested file Name.
      */
     public String getInputFileName() {
@@ -104,6 +123,9 @@ public class PluginInstallerArguments extends AbstractCommandLineArguments {
     }
 
     /** Get the digested input directory.
+     *
+     * Only valid for {@link OperationType#INSTALLDIR}.
+     *
      * @return Returns the digested input directory.
      */
     public Path getInputDirectory() {
@@ -124,9 +146,15 @@ public class PluginInstallerArguments extends AbstractCommandLineArguments {
         return list;
     }
 
+    /** Return the version to update to or null.
+     * @return the version or null
+     */
+    @Nullable public PluginVersion getUpdateVersion() {
+        return updateVersion;
+    }
+
     /**
      * Get operation to perform.
-     *
      * @return operation
      */
     @Nullable public OperationType getOperation() {
@@ -134,11 +162,23 @@ public class PluginInstallerArguments extends AbstractCommandLineArguments {
     }
 
     /** {@inheritDoc} */
+    // Checkstyle: CyclomaticComplexity OFF
     public void validate() throws IllegalArgumentException {
         super.validate();
 
-        if (getOtherArgs().size() > 2) {
-            throw new IllegalArgumentException("????");
+        final List<String> otherArgs = getOtherArgs();
+        if (otherArgs.size() > 1) {
+            final StringBuffer output = new StringBuffer().append('"');
+            for (int i = 2; i <= otherArgs.size() ; i++ ) {
+                output.append(otherArgs.get(i-1));
+                if (i == otherArgs.size()) {
+                    output.append('"');
+                } else {
+                    output.append(' ');
+                }
+            }
+            log.error("Unexpected extra arguments {}", output);
+            throw new IllegalArgumentException("Unexpected extra arguments");
         }
         if (list || fullList) {
             operation = OperationType.LIST;
@@ -146,14 +186,30 @@ public class PluginInstallerArguments extends AbstractCommandLineArguments {
                 log.error("Cannot List and Install in the same operation.");
                 throw new IllegalArgumentException("Cannot List and Install in the same operation.");
             }
-            return;
-        }
-        if (input != null) {
+            if (updatePluginId !=  null) {
+                log.error("Cannot List and Update in the same operation.");
+                throw new IllegalArgumentException("Cannot List and Update in the same operation.");
+            }
+        } else if (input != null) {
+            if (updatePluginId !=  null) {
+                log.error("Cannot Install and Update in the same operation.");
+                throw new IllegalArgumentException("Cannot List and Update in the same operation.");
+            }
             operation = decodeInput() ;
+        } else if (updatePluginId != null) {
+            pluginId = updatePluginId;
+            operation = OperationType.UPDATE;
+            if (forceUpdateVersion != null) {
+                updateVersion = new PluginVersion(forceUpdateVersion);
+            }
+        } else {
+            log.error("Missing qualifier. Options are : -l, -fl, -i, -u");
+            throw new IllegalArgumentException("Missing qualifier");
         }
     }
+    // Checkstyle: CyclomaticComplexity ON
 
-    /** Given an inout string, work out what the parts are.
+    /** Given an input string, work out what the parts are.
      * @return Whether this is a remote install or a local one.
      */
     private OperationType decodeInput() {
@@ -195,6 +251,9 @@ public class PluginInstallerArguments extends AbstractCommandLineArguments {
         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(String.format("  %-22s %s", "-i, --input <what>", "Install (file name or web address)"));
+        out.println(String.format("  %-22s %s", "-u, --update <what>", "update (plugin id)"));
+        out.println(String.format("  %-22s %s", "-fu, --force-update <version>",
+                "force version to update to (requires -u)"));
         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 8e7809229..7c2ee3c9f 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
@@ -18,6 +18,7 @@
 package net.shibboleth.idp.installer.plugin;
 
 import java.security.Security;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -41,6 +42,7 @@ import net.shibboleth.idp.Version;
 import net.shibboleth.idp.cli.AbstractIdPHomeAwareCommandLine;
 import net.shibboleth.idp.installer.plugin.impl.PluginInstaller;
 import net.shibboleth.idp.plugin.PluginDescription;
+import net.shibboleth.idp.plugin.PluginSupport.SupportLevel;
 import net.shibboleth.idp.plugin.PluginVersion;
 import net.shibboleth.idp.plugin.impl.PluginState;
 import net.shibboleth.idp.plugin.impl.PluginState.VersionInfo;
@@ -141,6 +143,10 @@ public final class PluginInstallerCLI extends AbstractIdPHomeAwareCommandLine<Pl
                     installer.installPlugin(args.getInputURL(), args.getInputFileName());
                     break;
 
+                case UPDATE:
+                    doUpdate(args.getPluginId() , args.getUpdateVersion());
+                    break;
+
                 default:
                     getLogger().error("Invalid operation");
                     return RC_INIT;
@@ -197,6 +203,97 @@ public final class PluginInstallerCLI extends AbstractIdPHomeAwareCommandLine<Pl
         }
     }
 
+    /** Find the best update version.  Helper function for {@linkplain #doUpdate(String, PluginVersion)}.
+     * @param plugin The Plugin
+     * @param state all about the plugin
+     * @return the best version (or null)
+     */
+    @Nullable private PluginVersion getBestVersion(final PluginDescription plugin, final PluginState state) {
+
+        final String idpVersionString = net.shibboleth.idp.Version.getVersion();
+        final PluginVersion myVersion = new PluginVersion(plugin.getMajorVersion(),
+                plugin.getMinorVersion(), plugin.getPatchVersion());
+
+        final PluginVersion idPVersion;
+        if (idpVersionString == null) {
+            idPVersion = new PluginVersion(4,1,0);
+            log.error("Could not determine IdP Version.  Assuming 4.1.0");
+        } else {
+            idPVersion = new PluginVersion(idpVersionString);
+        }
+
+        final List<PluginVersion> availableVersions = new ArrayList<>(state.getAvailableVersions().keySet());
+        availableVersions.sort(null);
+        log.debug("Considering versions {}", availableVersions);
+
+        for (int i = availableVersions.size()-1; i >= 0; i--) {
+            final PluginVersion version = availableVersions.get(i);
+            if (version.compareTo(myVersion) <= 0) {
+                log.debug("Version {} is less than or the same as {}. All done", version, myVersion);
+                return null;
+            }
+            final VersionInfo versionInfo = state.getAvailableVersions().get(version);
+            if (versionInfo.getSupportLevel() != SupportLevel.Current) {
+                log.debug("Version {} has suppprt level {}, ignoring", version, versionInfo.getSupportLevel());
+                continue;
+            }
+            if (!state.isSupportedWithIdPVersion(version, idPVersion)) {
+                log.debug("Version {} is not supported with idpVersion {}", version, idPVersion);
+                continue;
+            }
+            log.debug("Version {} is supported with idpVersion {}", version, idPVersion);
+            if (state.getUpdateURL(version) == null || state.getUpdateBaseName(version) == null) {
+                log.debug("Version {} is does not have update information", version);
+                continue;
+            }
+            return version;
+        }
+        return null;
+    }
+
+    /** Update the plugin.
+     * @param pluginId the pluginId or null.
+     * @param pluginVersion (optionally) the version to update to.
+     */
+    private void doUpdate(@Nonnull final String pluginId, @Nullable final PluginVersion pluginVersion) {
+        final List<PluginDescription> plugins = installer.getInstalledPlugins();
+        for (final PluginDescription plugin: plugins) {
+            if (pluginId.equals(plugin.getPluginId())) {
+                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 PluginVersion installVersion;
+                if (pluginVersion == null) {
+                    installVersion = getBestVersion(plugin, state);
+                    if (installVersion == null) {
+                        log.info("No Suitable update version available");
+                        break;
+                    }
+                } else {
+                    installVersion = pluginVersion;
+                    final Map<PluginVersion, VersionInfo> versions = state.getAvailableVersions();
+                    if (!versions.containsKey(installVersion)) {
+                        log.error("Specified version {} could not be found.  Available versions {}",
+                                installVersion, versions.keySet());
+                        return;
+                    }
+                }
+                // just use the tgz version - its an update so it should be jar files only
+                installer.installPlugin(state.getUpdateURL(installVersion),
+                        state.getUpdateBaseName(installVersion) + ".tar.gz");
+            }
+        }
+    }
+
+
     /** Print our more information about a plugin.
      * @param plugin what we are interested in.
      */
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 6c2577093..75990142b 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
@@ -18,7 +18,6 @@
 package net.shibboleth.idp.installer.plugin;
 
 import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.fail;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -43,7 +42,7 @@ import net.shibboleth.utilities.java.support.httpclient.HttpClientBuilder;
 @SuppressWarnings("javadoc")
 public class PluginCLITest extends BasePluginTest {
     
-    private final String RHINO_DISTRO = "https://build.shibboleth.net/nexus/service/local/repositories/releases/content/net/shibboleth/idp/plugin/scripting/idp-plugin-rhino-dist/0.1.0/idp-plugin-rhino-dist-0.1.0.tar.gz";
+    private final String RHINO_DISTRO = "https://build.shibboleth.net/nexus/service/local/repositories/releases/content/net/shibboleth/idp/plugin/scripting/idp-plugin-rhino-dist/0.1.2/idp-plugin-rhino-dist-0.1.2.tar.gz";
 
     private File plugin;
 
@@ -63,14 +62,27 @@ public class PluginCLITest extends BasePluginTest {
                 AbstractCommandLine.RC_INIT);
     }
 
-    @Test(enabled = false, dependsOnMethods = {"testRhinoLocal"}) public void testRhinoWeb() {
+    @Test(enabled = true, dependsOnMethods = {"testRhinoLocal"}) public void testRhinoWeb() {
             assertEquals(PluginInstallerCLI.runMain(new String[] { plugin.getAbsolutePath(),
                     "-i", RHINO_DISTRO,
                     "-p", "net.shibboleth.idp.plugin.rhino"}),
                     AbstractCommandLine.RC_OK);
     }
 
-    @Test(enabled = false) public void testRhinoLocal() {
+    @Test(dependsOnMethods = {"testRhinoWeb"})  public void testUpdate() {
+        assertEquals(PluginInstallerCLI.runMain(new String[] { plugin.getAbsolutePath(),
+                "-u", "net.shibboleth.idp.plugin.rhino"}),
+                AbstractCommandLine.RC_OK);
+    }
+
+    @Test(dependsOnMethods = {"testUpdate"})  public void testForceUpdate() {
+        assertEquals(PluginInstallerCLI.runMain(new String[] { plugin.getAbsolutePath(),
+                "-u", "net.shibboleth.idp.plugin.rhino",
+                "-fu", "0.1.2" }),
+                AbstractCommandLine.RC_OK);
+    }
+
+    @Test(enabled = true) public void testRhinoLocal() throws Exception {
         Path unpack = null;
         try {
             unpack = Files.createTempDirectory("rhinoLocal");
@@ -85,18 +97,13 @@ public class PluginCLITest extends BasePluginTest {
                     final OutputStream out = new BufferedOutputStream(new FileOutputStream(unpack.resolve("rhino.tar.gz.asc").toFile()))) {
                        in.transferTo(out);
                }
-            
-            assertEquals(PluginInstallerCLI.runMain(new String[] { plugin.getAbsolutePath(),
-                    "-p", "net.shibboleth.idp.plugin.rhino",
-                    "-i", unpack.resolve("rhino.tar.gz").toString()}),
-                    AbstractCommandLine.RC_IO);
+
+            final Path credentials = getIdpHome().resolve("credentials").resolve("net.shibboleth.idp.plugin.rhino");
+            Files.createDirectories(credentials);
             //
             // Populate the new key store
             //
-            final Path trustStorePath = getIdpHome().
-                    resolve("credentials").
-                    resolve("net.shibboleth.idp.plugin.rhino").
-                    resolve("truststore.asc");
+            final Path trustStorePath = credentials.resolve("truststore.asc");
             from = new ClassPathResource("credentials/truststore.asc");
             try (final InputStream in = from.getInputStream(); 
                     final OutputStream out = new BufferedOutputStream(new FileOutputStream(trustStorePath.toFile(), true))) {
@@ -109,8 +116,6 @@ public class PluginCLITest extends BasePluginTest {
                     "-i", unpack.resolve("rhino.tar.gz").toString(),
                     "-p", "net.shibboleth.idp.plugin.rhino"}),
                     AbstractCommandLine.RC_OK);
-        } catch (Exception e) {
-            fail("Failed" + e);
         } finally {
             if (unpack != null) {
                 PluginInstaller.deleteTree(unpack);

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


More information about the commits mailing list