[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