From 3d959f9d9f83c182517223fe7627b2357358b2f5 Mon Sep 17 00:00:00 2001 From: Patrick Dowler Date: Tue, 26 Mar 2024 09:57:33 -0700 Subject: [PATCH 1/5] cadc-vosi: update availability to allow startup in non-default mode avoid deprecated --- cadc-vosi/build.gradle | 2 +- .../ca/nrc/cadc/vosi/AvailabilityServlet.java | 32 +++++++++++++++---- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/cadc-vosi/build.gradle b/cadc-vosi/build.gradle index 755ce3b..898e70a 100644 --- a/cadc-vosi/build.gradle +++ b/cadc-vosi/build.gradle @@ -16,7 +16,7 @@ sourceCompatibility = 1.8 group = 'org.opencadc' -version = '1.4.5' +version = '1.4.6' description = 'OpenCADC VOSI server library' def git_url = 'https://github.com/opencadc/reg' diff --git a/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/AvailabilityServlet.java b/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/AvailabilityServlet.java index 85e66d0..93a5780 100644 --- a/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/AvailabilityServlet.java +++ b/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/AvailabilityServlet.java @@ -74,10 +74,12 @@ import ca.nrc.cadc.log.ServletLogInfo; import ca.nrc.cadc.log.WebServiceLogInfo; import ca.nrc.cadc.net.NetUtil; +import ca.nrc.cadc.util.InvalidConfigException; import ca.nrc.cadc.util.MultiValuedProperties; import ca.nrc.cadc.util.PropertiesReader; import ca.nrc.cadc.util.StringUtil; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.security.Principal; import java.util.HashSet; import java.util.List; @@ -103,6 +105,7 @@ public class AvailabilityServlet extends HttpServlet { private static final long serialVersionUID = 201003131300L; private static final String AVAILABILITY_PROPERTIES = "cadc-vosi.properties"; + private static final String MODE_KEY = "startupMode"; private static final String USERS_PROPERTY = "user"; private String pluginClassName; @@ -115,6 +118,27 @@ public void init(ServletConfig config) this.appName = config.getServletContext().getContextPath().substring(1).replaceAll("/", "-"); this.pluginClassName = config.getInitParameter(AvailabilityPlugin.class.getName()); log.info("application: " + appName + " plugin impl: " + pluginClassName); + + MultiValuedProperties mvp = getAvailabilityProperties(); + String startupMode = mvp.getFirstPropertyValue(MODE_KEY); + if (startupMode != null) { + AvailabilityPlugin ap = loadPlugin(); + ap.setState(startupMode); + } + } + + private AvailabilityPlugin loadPlugin() throws InvalidConfigException { + try { + Class wsClass = Class.forName(pluginClassName); + AvailabilityPlugin ap = (AvailabilityPlugin) wsClass.getConstructor().newInstance(); + ap.setAppName(appName); + log.debug("loaded: " + wsClass); + return ap; + } catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException + | InstantiationException | NoSuchMethodException | SecurityException + | InvocationTargetException ex) { + throw new InvalidConfigException("failed to load AvailabilityPlugin: " + pluginClassName, ex); + } } @Override @@ -128,9 +152,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) logInfo.setSubject(subject); log.info(logInfo.start()); - Class wsClass = Class.forName(pluginClassName); - AvailabilityPlugin ap = (AvailabilityPlugin) wsClass.newInstance(); - ap.setAppName(appName); + AvailabilityPlugin ap = loadPlugin(); String detail = request.getParameter("detail"); if (detail != null && detail.equals("min")) { @@ -174,9 +196,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) logInfo.setSubject(subject); log.info(logInfo.start()); - Class wsClass = Class.forName(pluginClassName); - AvailabilityPlugin ap = (AvailabilityPlugin) wsClass.newInstance(); - ap.setAppName(appName); + AvailabilityPlugin ap = loadPlugin(); IdentityManager im = AuthenticationUtil.getIdentityManager(); String caller = im.toDisplayString(subject); From b73a2381bd8aeaab967c024aae7eb454bd3fc00e Mon Sep 17 00:00:00 2001 From: Patrick Dowler Date: Tue, 26 Mar 2024 10:06:23 -0700 Subject: [PATCH 2/5] update cadc-vosi/README --- cadc-vosi/README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cadc-vosi/README.md b/cadc-vosi/README.md index 2480044..72aeb94 100644 --- a/cadc-vosi/README.md +++ b/cadc-vosi/README.md @@ -14,13 +14,44 @@ change the service state via HTTP POST to the `/availability` endpoint. ```properties user = {X509 distinguished name} user = ... + +# optional mode at startup: Offline, ReadOnly, ReadWrite (default) +startupMode = ReadWrite|ReadOnly|Offline ``` + For the X509 distinguished name, the availability endpoint can successfully authorise the user even when the associated AAI system is unavailable, so this mechanism is more robust as it does not depend on any other functioning component. +If an optional _startupMode_ is configured, the availability servlet will create the service-specific +AvailabilityPlugin and call `setState`. The behaviour is completely in rthe control of the service +and how it implements the plugin. + ## TODO - rewrite the AvailabilityServlet as a RestAction based on the `cadc-rest` library - add ability to configure users and groups consistent with the `cadc-log` library - remove the old CapabilitiesServlet - developer documentation (how to include in web.xml) + +## temporary developer documentation +The following (or something like it) is needed in the `web.xml` deployment descriptor to add +an /avaailability endpoint to a service: +```xml + + + AvailabilityServlet + ca.nrc.cadc.vosi.AvailabilityServlet + + ca.nrc.cadc.vosi.AvailabilityPlugin + fully.qualified.classname.for.AvailabilityPluginImpl + + 2 + + + AvailabilityServlet + /availability + +``` +Especially if using the _startupMode_, putting this servlet early in the load sequence (2 above, before +service specific endpoints and init) will ensure that the startup mode is set before other init happens. + From 2199b34d54217a7998e5429a901d3f1cb7f231a3 Mon Sep 17 00:00:00 2001 From: Patrick Dowler Date: Tue, 26 Mar 2024 11:00:00 -0700 Subject: [PATCH 3/5] add example state change to README --- cadc-vosi/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cadc-vosi/README.md b/cadc-vosi/README.md index 72aeb94..ca00a2a 100644 --- a/cadc-vosi/README.md +++ b/cadc-vosi/README.md @@ -8,6 +8,15 @@ cadc-tap-schema library. In addition to the normal VOSI API, the VOSI-availability component supports optional changing of the service state. Supported states: ReadWrite (normal), ReadOnly, and Offline. +Set state example: +``` +curl --cert -d state=ReadOnly https://example.net/srv/availability +``` +Get example: +``` +curl https://example.net/srv/availability +``` + ## cadc-vosi.properties This config file (optional) allows deployers to specify users that are allowed to change the service state via HTTP POST to the `/availability` endpoint. From 342d83d1b492a3da8d122af2af63be8128ef2533 Mon Sep 17 00:00:00 2001 From: Patrick Dowler Date: Tue, 26 Mar 2024 11:32:19 -0700 Subject: [PATCH 4/5] typo --- cadc-vosi/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadc-vosi/README.md b/cadc-vosi/README.md index ca00a2a..46c3058 100644 --- a/cadc-vosi/README.md +++ b/cadc-vosi/README.md @@ -33,7 +33,7 @@ user even when the associated AAI system is unavailable, so this mechanism is mo as it does not depend on any other functioning component. If an optional _startupMode_ is configured, the availability servlet will create the service-specific -AvailabilityPlugin and call `setState`. The behaviour is completely in rthe control of the service +AvailabilityPlugin and call `setState`. The behaviour is completely in the control of the service and how it implements the plugin. ## TODO From 48dcef581e76469f5b9707eed5b731e51fcae613 Mon Sep 17 00:00:00 2001 From: Patrick Dowler Date: Tue, 26 Mar 2024 12:56:52 -0700 Subject: [PATCH 5/5] move getLibraryVersion to cadc-rest --- cadc-vosi/build.gradle | 2 +- .../java/ca/nrc/cadc/vosi/CapInitAction.java | 41 ++----------------- 2 files changed, 4 insertions(+), 39 deletions(-) diff --git a/cadc-vosi/build.gradle b/cadc-vosi/build.gradle index 898e70a..6ab47c1 100644 --- a/cadc-vosi/build.gradle +++ b/cadc-vosi/build.gradle @@ -27,7 +27,7 @@ dependencies { compile 'javax.servlet:javax.servlet-api:[3.1.0,)' compile 'org.opencadc:cadc-util:[1.6,)' - compile 'org.opencadc:cadc-rest:[1.3.6,)' + compile 'org.opencadc:cadc-rest:[1.3.20,)' compile 'org.opencadc:cadc-registry:[1.3.5,)' runtime 'org.jdom:saxpath:1.0-FCS' diff --git a/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/CapInitAction.java b/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/CapInitAction.java index 2c166d3..766b21b 100644 --- a/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/CapInitAction.java +++ b/cadc-vosi/src/main/java/ca/nrc/cadc/vosi/CapInitAction.java @@ -70,6 +70,7 @@ import ca.nrc.cadc.reg.Capabilities; import ca.nrc.cadc.reg.CapabilitiesReader; import ca.nrc.cadc.rest.InitAction; +import ca.nrc.cadc.rest.Version; import ca.nrc.cadc.util.StringUtil; import java.io.StringReader; @@ -189,7 +190,7 @@ public void doInit() { } try { - String version = findLibraryVersion(CapInitAction.class); + Version version = getLibraryVersion(CapInitAction.class); jndiKey = componentID + ".version"; try { @@ -198,46 +199,10 @@ public void doInit() { } catch (NamingException e) { log.debug("no previously bound value, continuting"); } - initContext.bind(jndiKey, version); + initContext.bind(jndiKey, version.getMajorMinor()); log.info("doInit: version=" + version + " stored via JNDI: " + jndiKey); } catch (Exception ex) { throw new IllegalArgumentException("CONFIG: failed to set version flag", ex); } } - - // TODO: move this code up to cadc-rest or cadc-util - private String findLibraryVersion(Class probe) { - String ret = "no-version-found"; - String rname = probe.getSimpleName() + ".class"; - try { - - URL resURL = probe.getResource(rname); - log.debug("library URL: " + resURL); - // assume assume maven-central naming conventions for jar - // jar:file:/path/to/{library}-{ver}.jar!/package/subpackage/{rname} - if (resURL != null) { - String[] parts = resURL.toExternalForm().split("[:!]"); - int i = 0; - for (String p : parts) { - if (p.endsWith(".jar")) { - int s = p.lastIndexOf('/'); - String ver = p.substring(s + 1); // {library}-{ver}.jar - ver = ver.replace(".jar", ""); // {library}-{ver} - - // extract {major}.{minor} only - String[] mmp = ver.split("\\."); - if (mmp.length > 2) { - ret = mmp[0] + "." + mmp[1]; - } else { - ret = ver; - } - } - } - } - } catch (Exception ex) { - log.error("failed to find version for " + rname + " from classpath", ex); - } - - return ret; - } }