[java-identity-provider] 03/03: IDP-2114 Add metrics for installed plugins and modules
Rod Widdowson
rdw at steadingsoftware.com
Tue Jun 20 14:51:29 UTC 2023
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=96a77deebb3fd462314c2c40924325aa90ab4775
commit 96a77deebb3fd462314c2c40924325aa90ab4775
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Tue Jun 20 15:17:34 2023 +0100
IDP-2114 Add metrics for installed plugins and modules
https://shibboleth.atlassian.net/browse/IDP-2114
Guages to report
* All Plugins' and versions
* All Plugin supported and update states
* IdP Update state
---
.../admin/impl/InstallableComponentGuageSet.java | 257 +++++++++++++++++++++
.../shibboleth/idp}/plugin/impl/PluginInfo.java | 4 +-
.../net/shibboleth/idp/conf/admin-system.xml | 6 +
.../shibboleth/idp/module/conf/admin/metrics.xml | 1 +
.../installer/plugin/impl/PluginInstallerCLI.java | 1 +
.../idp/installer/plugin/impl/PluginState.java | 1 +
6 files changed, 268 insertions(+), 2 deletions(-)
diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/InstallableComponentGuageSet.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/InstallableComponentGuageSet.java
new file mode 100644
index 000000000..520e58f57
--- /dev/null
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/InstallableComponentGuageSet.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.admin.impl;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ServiceLoader;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.hc.client5.http.classic.HttpClient;
+import org.jetbrains.annotations.NotNull;
+import org.opensaml.security.httpclient.HttpClientSecurityParameters;
+import org.slf4j.Logger;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Metric;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.MetricSet;
+
+import net.shibboleth.idp.Version;
+import net.shibboleth.idp.plugin.IdPPlugin;
+import net.shibboleth.idp.plugin.impl.PluginInfo;
+import net.shibboleth.profile.installablecomponent.InstallableComponentInfo;
+import net.shibboleth.profile.installablecomponent.InstallableComponentInfo.VersionInfo;
+import net.shibboleth.profile.installablecomponent.InstallableComponentSupport;
+import net.shibboleth.profile.installablecomponent.InstallableComponentSupport.SupportLevel;
+import net.shibboleth.profile.installablecomponent.InstallableComponentVersion;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.NullableElements;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Guage set to report the Plugins' & IdP installation and update statuses.
+ */
+/**
+ *
+ */
+public class InstallableComponentGuageSet extends AbstractIdentifiableInitializableComponent implements MetricSet {
+
+ /** Logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(InstallableComponentGuageSet.class);
+
+ /** Default prefix for metrics. */
+ @Nonnull @NotEmpty private static final String DEFAULT_METRIC_NAME = "net.shibboleth.idp.installedcomponent";
+
+ /** The map of gauges. */
+ @Nonnull @NonnullElements private final Map<String,Metric> gauges = new HashMap<>();
+
+ /** Where to look for update information. */
+ @Nonnull private List<URL> idpUpdateUrls = CollectionSupport.emptyList();
+
+ /** How to reach out. */
+ @NonnullAfterInit private HttpClient httpClient;
+
+ /** any security parameters needed. */
+ @Nullable private HttpClientSecurityParameters securityParams;
+
+ /** IdP Version to check. */
+ @NonnullAfterInit private InstallableComponentVersion idpVersion;
+
+ public InstallableComponentGuageSet() {
+ gauges.put(MetricRegistry.name(DEFAULT_METRIC_NAME, "plugins", "list"),
+ new Gauge<Map<String, InstallableComponentVersion>>() {
+ public Map<String, InstallableComponentVersion> getValue() {
+ return getPluginList();
+ }
+ });
+ gauges.put(MetricRegistry.name(DEFAULT_METRIC_NAME, "plugins", "details"),
+ new Gauge<Map<String, InstallableComponentDetails>>() {
+ public Map<String, InstallableComponentDetails> getValue() {
+ return getPluginDetails();
+ }
+ });
+ gauges.put(MetricRegistry.name(DEFAULT_METRIC_NAME, "idp", "details"),
+ new Gauge<InstallableComponentDetails>() {
+ public InstallableComponentDetails getValue() {
+ return getIdPDetails();
+ }
+ });
+
+ }
+
+ /** Set where to look for idp update info.
+ * @param urls what to set.
+ */
+ public void setIdpUpdateUrls(@Nonnull final List<URL> urls) {
+ idpUpdateUrls = urls;
+ }
+
+ /** Set any {@link HttpClientSecurityParameters}.
+ * @param params what to set.
+ */
+ public void setSecurityParams(@Nullable final HttpClientSecurityParameters params) {
+ securityParams = params;
+ }
+
+ /** Set the {@link HttpClient} to use.
+ * @param client what to set.
+ */
+ public void setHttpClient(@Nonnull final HttpClient client) {
+ httpClient = Constraint.isNotNull(client, "HttpClient cannot be null");
+ }
+
+ /** Null safe IdP Version
+ * @return Returns the idPVersion.
+ */
+ @Nonnull InstallableComponentVersion getIdPVersion() {
+ checkComponentActive();
+ assert idpVersion!=null;
+ return idpVersion;
+ }
+
+ /** Return the list of installed components and their versions
+ * @return a Map where the key is the PluginId and the value is the version.
+ */
+ @Nonnull @NotLive private Map<String, InstallableComponentVersion> getPluginList() {
+ final Map<String, InstallableComponentVersion> result = new HashMap<>();
+ final Iterator<IdPPlugin> plugins = ServiceLoader.load(IdPPlugin.class).iterator();
+ while (plugins.hasNext()) {
+ final IdPPlugin plugin = plugins.next();
+ result.put(plugin.getPluginId(), new InstallableComponentVersion(plugin));
+ }
+ return CollectionSupport.copyToMap(result);
+ }
+
+ private Map<String, InstallableComponentDetails> getPluginDetails() {
+ @NullableElements final Map<URL, Properties> pluginInfoCache = new HashMap<>();
+ final Map<String, InstallableComponentDetails> result = new HashMap<>();
+ final Iterator<IdPPlugin> plugins = ServiceLoader.load(IdPPlugin.class).iterator();
+ while (plugins.hasNext()) {
+ final IdPPlugin plugin = plugins.next();
+ assert plugin!=null;
+ final Properties properties = lookupIdPProperties(plugin, pluginInfoCache);
+ if (properties==null) {
+ log.error("Could not located Plugin version information");
+ continue;
+ }
+ final InstallableComponentInfo info = new PluginInfo(plugin.getPluginId(), properties);
+ final InstallableComponentVersion pluginVersion = new InstallableComponentVersion(plugin);
+ final VersionInfo verInfo = info.getAvailableVersions().get(pluginVersion);
+ if (verInfo == null) {
+ log.error("Could not located Plugin version information");
+ continue;
+ }
+ final InstallableComponentVersion newPluginVersion = InstallableComponentSupport.getBestVersion(getIdPVersion(), pluginVersion, info);
+ result.put(plugin.getPluginId(), new InstallableComponentDetails(verInfo.getSupportLevel(), newPluginVersion));
+ }
+ return CollectionSupport.copyToMap(result);
+ }
+
+ /** Look in the cache for the URL and return the properties if its there.
+ * Otherwise reach out to the URP and load the properties
+ * @param plugin the {@link IdPPlugin} to consider.
+ * @param pluginInfoCache the cache of already looked up info. Also serves as a negative cache.
+ * @return
+ */
+ @Nullable private Properties lookupIdPProperties(@NotNull final IdPPlugin plugin, @NullableElements final Map<URL, Properties> pluginInfoCache) {
+ final List<URL> urls;
+ try {
+ urls = plugin.getUpdateURLs();
+ } catch (final IOException e) {
+ log.error("Could not locate plugin {} update urls", plugin.getPluginId(), e);
+ return null;
+ }
+ for (final URL url:urls) {
+ if (pluginInfoCache.containsKey(url)) {
+ return pluginInfoCache.get(url);
+ }
+ }
+ assert httpClient != null;
+ final Properties result = InstallableComponentSupport.loadInfo(urls, httpClient, securityParams);
+ for (final URL url:urls) {
+ // Note - negative caching too.
+ pluginInfoCache.put(url, result);
+ }
+ return result;
+ }
+
+ /** Return information about the Installation update state of the IdP.
+ * @return a {@link InstallableComponentDetails}
+ */
+ @Nullable private InstallableComponentDetails getIdPDetails() {
+ try {
+ assert httpClient!=null;
+ final Properties properties = InstallableComponentSupport.loadInfo(idpUpdateUrls, httpClient, securityParams);
+ if (properties == null) {
+ log.error("Could not locate IdP update information");
+ return null;
+ }
+ final InstallableComponentInfo info = new IdPInfo(properties);
+ final VersionInfo verInfo = info.getAvailableVersions().get(getIdPVersion());
+ if (verInfo == null) {
+ log.error("Could not located IdP version information");
+ return null;
+ }
+ final InstallableComponentVersion newIdPVersion = InstallableComponentSupport.getBestVersion(getIdPVersion(), getIdPVersion(), info);
+ return new InstallableComponentDetails(verInfo.getSupportLevel(), newIdPVersion);
+ } catch (final Throwable t) {
+ log.error("Check for IdP update status failed unexpectedly", t);
+ return null;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+ if (httpClient == null) {
+ throw new ComponentInitializationException("Http Client was null");
+ }
+ final String idpVersionStr = Version.getVersion();
+ if (idpVersionStr == null) {
+ // So things work inside eclipse.
+ log.error("Could not find Current IdP Version, assuming V5.0.0");
+ idpVersion = new InstallableComponentVersion(5,0,0);
+ } else {
+ idpVersion = new InstallableComponentVersion(idpVersionStr);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Map<String, Metric> getMetrics() {
+ return gauges;
+ }
+
+ record InstallableComponentDetails(@Nonnull @NotEmpty SupportLevel supportedState, @Nullable InstallableComponentVersion updateVersion) { };
+}
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInfo.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/plugin/impl/PluginInfo.java
similarity index 96%
rename from idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInfo.java
rename to idp-admin-impl/src/main/java/net/shibboleth/idp/plugin/impl/PluginInfo.java
index fd418fa86..4524f336e 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInfo.java
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/plugin/impl/PluginInfo.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package net.shibboleth.idp.installer.plugin.impl;
+package net.shibboleth.idp.plugin.impl;
import java.util.Properties;
@@ -28,7 +28,7 @@ import net.shibboleth.profile.installablecomponent.InstallableComponentVersion;
import net.shibboleth.shared.primitive.StringSupport;
/**
- * Information about a Plugin
+ * Information about a Plugin.
*/
public class PluginInfo extends InstallableComponentInfo {
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
index 17d349ac9..95f271e45 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
@@ -340,6 +340,12 @@
c:metricName="net.shibboleth.idp.managedbean"
p:service-ref="shibboleth.ManagedBeanService" />
+ <bean id="shibboleth.metrics.InstallableComponents"
+ class="net.shibboleth.idp.admin.impl.InstallableComponentGuageSet" lazy-init="true"
+ p:idpUpdateUrls-ref="%{idp.updateCheck.urls:shibboleth.IdPUpdateCheckUrls}"
+ p:httpClient-ref="%{idp.updateCheck.httpClient:shibboleth.InternalHttpClient}"
+ p:securityParams="#{ environment.containsProperty('idp.updateCheck.httpSecurityParameters') ? getObject('idp.updateCheck.httpSecurityParameters') :null}"/>
+
<util:list id="shibboleth.IdPUpdateCheckUrls">
<value>https://shibboleth.net/downloads/identity-provider/plugins/idp-versions.properties</value>
<value>http://plugins.shibboleth.net/idp-versions.properties</value>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/metrics.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/metrics.xml
index 782d707a3..ea6bb25f4 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/metrics.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/metrics.xml
@@ -32,6 +32,7 @@
<ref bean="shibboleth.metrics.CASServiceRegistryGaugeSet" />
<ref bean="shibboleth.metrics.ManagedBeanGaugeSet" />
<ref bean="shibboleth.metrics.ModuleGaugeSet" />
+ <ref bean="shibboleth.metrics.InstallableComponents" />
<!--
<bean class="com.codahale.metrics.jvm.CachedThreadStatesGaugeSet"
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerCLI.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerCLI.java
index fd30ac38e..75bc7d4de 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerCLI.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginInstallerCLI.java
@@ -48,6 +48,7 @@ import net.shibboleth.idp.Version;
import net.shibboleth.idp.cli.AbstractIdPHomeAwareCommandLine;
import net.shibboleth.idp.installer.InstallerSupport;
import net.shibboleth.idp.plugin.IdPPlugin;
+import net.shibboleth.idp.plugin.impl.PluginInfo;
import net.shibboleth.profile.installablecomponent.InstallableComponentInfo;
import net.shibboleth.profile.installablecomponent.InstallableComponentSupport;
import net.shibboleth.profile.installablecomponent.InstallableComponentVersion;
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginState.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginState.java
index a03dd3248..f6d7a2b1a 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginState.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/plugin/impl/PluginState.java
@@ -33,6 +33,7 @@ import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import net.shibboleth.idp.plugin.IdPPlugin;
+import net.shibboleth.idp.plugin.impl.PluginInfo;
import net.shibboleth.profile.installablecomponent.InstallableComponentInfo;
import net.shibboleth.profile.installablecomponent.InstallableComponentVersion;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list