diff --git a/container/features/pom.xml b/container/features/pom.xml index 420582065104..e31465248a22 100644 --- a/container/features/pom.xml +++ b/container/features/pom.xml @@ -307,6 +307,8 @@ opennms-poller-monitors-core opennms-telemetry-daemon opennms-timeseries-api + opennms-timeseries-api + opennms-grpc-exporter vaadin @@ -812,6 +814,12 @@ ${project.version} provided + + org.opennms.features.grpc + org.opennms.features.grpc.exporter + ${project.version} + provided + org.opennms.container extender diff --git a/container/features/src/main/resources/features.xml b/container/features/src/main/resources/features.xml index 09f6e250214a..e7c663c0d539 100644 --- a/container/features/src/main/resources/features.xml +++ b/container/features/src/main/resources/features.xml @@ -2060,4 +2060,12 @@ mvn:org.opennms.features/org.opennms.features.newts/${project.version} + + opennms-integration-api + mvn:com.google.protobuf/protobuf-java/${protobufVersion} + mvn:org.mapstruct/mapstruct/${mapstructVersion} + mvn:org.opennms.core.grpc/org.opennms.core.grpc.osgi/${project.version} + mvn:org.opennms.features.grpc/org.opennms.features.grpc.exporter/${project.version} + + diff --git a/core/snmp/impl-joesnmp/src/test/java/org/opennms/netmgt/snmp/joesnmp/NMS16395Test.java b/core/snmp/impl-joesnmp/src/test/java/org/opennms/netmgt/snmp/joesnmp/NMS16395Test.java index fcd18a1eb761..829178209655 100644 --- a/core/snmp/impl-joesnmp/src/test/java/org/opennms/netmgt/snmp/joesnmp/NMS16395Test.java +++ b/core/snmp/impl-joesnmp/src/test/java/org/opennms/netmgt/snmp/joesnmp/NMS16395Test.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/core/snmp/impl-snmp4j/src/test/java/org/opennms/netmgt/snmp/snmp4j/NMS16395Test.java b/core/snmp/impl-snmp4j/src/test/java/org/opennms/netmgt/snmp/snmp4j/NMS16395Test.java index 000b7b29dcd5..11ba46ef767a 100644 --- a/core/snmp/impl-snmp4j/src/test/java/org/opennms/netmgt/snmp/snmp4j/NMS16395Test.java +++ b/core/snmp/impl-snmp4j/src/test/java/org/opennms/netmgt/snmp/snmp4j/NMS16395Test.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SNMPSetBuilder.java b/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SNMPSetBuilder.java index 8cda943195b0..7156644875bd 100644 --- a/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SNMPSetBuilder.java +++ b/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SNMPSetBuilder.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SnmpSetRequestDTO.java b/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SnmpSetRequestDTO.java index 3d78b4f4f80b..aa890a54ac9e 100644 --- a/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SnmpSetRequestDTO.java +++ b/core/snmp/proxy-rpc-impl/src/main/java/org/opennms/netmgt/snmp/proxy/common/SnmpSetRequestDTO.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/debian/changelog b/debian/changelog index d9e4dc772aec..901562fc27ca 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +opennms (33.1.2-1) stable; urgency=medium + + * Release 33.1.2 contains a bug fix and a new feature. + + For details on what has changed, see: + https://docs.opennms.com/horizon/33.1.2/index.html + + -- OpenNMS Release Manager Tue, 07 Jan 2024 10:30:00 -0500 + opennms (33.1.1-1) stable; urgency=medium * Release 33.1.1 contains bug fixes, security updates and new features. diff --git a/docs/modules/deployment/pages/minion/message-broker/kafka.adoc b/docs/modules/deployment/pages/minion/message-broker/kafka.adoc index a1d25360de5f..76b67cacc44b 100644 --- a/docs/modules/deployment/pages/minion/message-broker/kafka.adoc +++ b/docs/modules/deployment/pages/minion/message-broker/kafka.adoc @@ -65,7 +65,7 @@ The following example uses SASL/SCRAM with TLS: ---- config:edit org.opennms.core.ipc.kafka config:property-set bootstrap.servers my-kafka-ip-1:9096,my-kafka-ip-2:9096 -config:property-set security.protocol=SASL_SSL +config:property-set security.protocol SASL_SSL config:property-set sasl.mechanism SCRAM-SHA-512 config:property-set sasl.jaas.config 'org.apache.kafka.common.security.scram.ScramLoginModule required username="opennms-ipc" password="kafka";' config:update diff --git a/docs/modules/deployment/pages/minion/system-requirements.adoc b/docs/modules/deployment/pages/minion/system-requirements.adoc index a8f9c3c1690a..b8acf14ea754 100644 --- a/docs/modules/deployment/pages/minion/system-requirements.adoc +++ b/docs/modules/deployment/pages/minion/system-requirements.adoc @@ -35,12 +35,11 @@ OpenNMS {page-component-title} runs on the following operating systems: | Operating System | Supported Versions (64-bit) | RHEL -| {compatible-rhel7} + -{compatible-rhel8} +| {compatible-rhel8} + +{compatible-rhel9} | CentOS -| {compatible-centos7} + -{compatible-centos-stream} +| {compatible-centos-stream} ifeval::["{page-component-title}" == "Horizon"] | Debian diff --git a/docs/modules/deployment/pages/time-series-storage/newts/newts.adoc b/docs/modules/deployment/pages/time-series-storage/newts/newts.adoc index 1b19961bcb72..7f96a849687a 100644 --- a/docs/modules/deployment/pages/time-series-storage/newts/newts.adoc +++ b/docs/modules/deployment/pages/time-series-storage/newts/newts.adoc @@ -9,65 +9,80 @@ This section describes how to configure your {page-component-title} instance to Follow these steps to set up Newts on your {page-component-title} instance: -. Create a configuration file with your time series database settings: -+ +.Create a configuration file with the time series storage settings [source, console] +---- sudo vi etc/opennms.properties.d/timeseries.properties +---- -. Configure the storage strategy: -+ +.Configure Newts as the time series strategy [source, properties] ---- -org.opennms.rrd.storeByForeignSource=true <1> -org.opennms.timeseries.strategy=newts <2> +# Configure storage strategy +org.opennms.rrd.storeByForeignSource=true<1> +org.opennms.timeseries.strategy=newts<2> + +# One year in seconds +org.opennms.newts.config.ttl=31540000<3> + +# Seven days in seconds +org.opennms.newts.config.resource_shard=604800<4> + +# Configure Newts time series storage connection +org.opennms.newts.config.driver_settings_file=/opt/opennms/etc/cassandra-driver.conf<5> ---- -<1> Associate time series data using the foreign source and ID instead of the database-generated node ID. -<2> Set time series strategy to use Newts. -If you are enabling the xref:time-series-storage/timeseries/time-series-storage.adoc#ga-dual-write-newts[dual write plugin] on an existing {page-component-title} installation and you want to keep historical metrics, make sure that the written data has expired before you set `org.opennms.timeseries.strategy` to `newts`. -. Configure the Newts time series storage connection: -+ -[source, properties] +<1> Associate time series data by the foreign ID instead of the database-generated Node-ID. +<2> Set time series strategy to use `newts`. +<3> Retention rate for the time series data. +<4> Shard metrics every 7 days. +<5> The path to your driver configuration file + +.Create a configuration file with the time series storage settings +[source, console] ---- -org.opennms.newts.config.hostname=cassandra-ip1,cassandra-ip2 <1> -org.opennms.newts.config.keyspace=newts <2> -org.opennms.newts.config.port=9042 <3> +sudo vi etc/cassandra-driver.conf ---- -<1> Host or IP addresses of the Cassandra cluster nodes. -Can be a comma-separated list. -<2> Name of the keyspace which is initialized and used. -<3> Port to connect to Cassandra. -. Set the retention rate and shard rate: -+ +. Configure the Cassandra driver settings [source, properties] ---- -# One year in seconds -org.opennms.newts.config.ttl=31540000 <1> - -# Seven days in seconds -org.opennms.newts.config.resource_shard=604800 <2> +datastax-java-driver { + basic.contact-points = [ "example-node1:9042", "example-node2:9042" ]<1> + session-keyspace = "newts"<2> + basic.load-balancing-policy { + local-datacenter = datacenter1<3> + } + advanced.auth-provider { + class = PlainTextAuthProvider <4> + username = cassandra + password = cassandra + } +} ---- -<1> Retention rate for the time series data. -<2> Shard metrics every 7 days. -. (Optional) If your {page-component-title} data collection or polling intervals have been modified, set the query minimum and heartbeat rates: +<1> `Hostname:port` or `IP address:port` of one or more Cassandra cluster nodes. +<2> Name of the keyspace which is initialized and used. +<3> The local datacenter as defined by your Cassandra configuration +<4> The authentication provider to use with the supplied credentials + +.(Optional) If your {page-component-title} data collection or polling intervals have been modified, set the query minimum and heartbeat rates: + [source, properties] ---- org.opennms.newts.query.minimum_step=30000 <1> -org.opennms.newts.query.heartbeat=45000 <2> +org.opennms.newts.query.heartbeat=450000 <2> ---- <1> The shortest collection interval configured for any collectable or pollable service, in milliseconds (in this case, 30 seconds). <2> The communication interval for the Newts service, in milliseconds. -Should be set to 1.5 times the `maximum` value of the collection interval configured for any collectable or pollable service, in milliseconds (in this case, 45 seconds). +Should be set to 1.5 times the `maximum` value of the collection interval configured for any collectable or pollable service, in milliseconds (in this case, 450 seconds). -. Initialize the Newts schema in Cassandra: +.Initialize the Newts schema in Cassandra: + [source, console] bin/newts init -. Connect to Cassandra using the CQL shell: +.Connect to Cassandra using the CQL shell: + [source, console] ---- @@ -79,7 +94,7 @@ cd ${CASSANDRA_HOME}/bin After you have set the time series database to Newts and configured its settings, you must verify your setup and restart {page-component-title}: -. Verify keyspace initialization: +.Verify keyspace initialization: + [source, console] ---- @@ -88,7 +103,7 @@ describe table terms; describe table samples; ---- -. Restart {page-component-title} to apply your changes and verify your configuration: +.Restart {page-component-title} to apply your changes and verify your configuration: + [source, console] systemctl restart opennms diff --git a/docs/modules/operation/nav.adoc b/docs/modules/operation/nav.adoc index 6f4f58aa48ab..36f5e886c336 100644 --- a/docs/modules/operation/nav.adoc +++ b/docs/modules/operation/nav.adoc @@ -198,6 +198,8 @@ *** xref:deep-dive/kafka-producer/configure-kafka.adoc[] *** xref:deep-dive/kafka-producer/shell-commands.adoc[] +** xref:deep-dive/grpc-exporter/grpc-exporter.adoc[] + ** xref:deep-dive/alarm-correlation/situation-feedback.adoc[] ** xref:deep-dive/meta-data.adoc[] ** xref:deep-dive/search.adoc[] diff --git a/docs/modules/operation/pages/deep-dive/grpc-exporter/grpc-exporter.adoc b/docs/modules/operation/pages/deep-dive/grpc-exporter/grpc-exporter.adoc new file mode 100644 index 000000000000..f22cdf0148b3 --- /dev/null +++ b/docs/modules/operation/pages/deep-dive/grpc-exporter/grpc-exporter.adoc @@ -0,0 +1,41 @@ += Grpc Exporter +:description: Learn how the gRPC Exporter enables {page-component-title} to forward the status of monitored services to external applications. + +The Grpc Exporter feature allows {page-component-title} to forward the status of all monitored services to external applications via the gRPC protocol. + +These objects are encoded using link:https://developers.google.com/protocol-buffers/[Google Protocol Buffers (GPB)]. +See `monitored-services.proto` in the corresponding source distribution for the model definitions. + +== Configure gRPC Exporter + +[source, karaf] +---- +$ ssh -p 8101 admin@localhost +... +admin@opennms()> config:edit org.opennms.features.grpc.exporter +admin@opennms()> config:property-set host bsm.onmshs.local:1440 <1> +admin@opennms()> config:property-set tls.cert.path /opt/opennms/etc/tls.cert <2> +admin@opennms()> config:property-set tls.enabled false <3> +admin@opennms()> config:property-set snapshot.interval 3600 false <4> +admin@opennms()> config:update +---- + +<1> Set the hostname of the external gRPC application. +<2> Configure the path to the TLS certificate. +<3> TLS is enabled by default. For testing purposes, it can be disabled by setting this value to false. +<4> Set the interval (in seconds) at which the complete snapshot of services will be sent to the gRPC server. + +== Enable gRPC Exporter + +Install the `opennms-grpc-exporter` feature from the same shell using: + +[source, karaf] +---- +feature:install opennms-grpc-exporter +---- + +To ensure the feature is installed on subsequent restarts, add `opennms-grpc-exporter` to a file in featuresBoot.d: +[source, console] +---- +echo "opennms-grpc-exporter" | sudo tee ${OPENNMS_HOME}/etc/featuresBoot.d/grpc-exporter.boot +---- \ No newline at end of file diff --git a/docs/modules/releasenotes/pages/changelog.adoc b/docs/modules/releasenotes/pages/changelog.adoc index 9b2cbf3bb43d..b8964ecaa293 100644 --- a/docs/modules/releasenotes/pages/changelog.adoc +++ b/docs/modules/releasenotes/pages/changelog.adoc @@ -1,6 +1,23 @@ [[release-33-changelog]] = Changelog +[[releasenotes-changelog-33.1.2]] + +== Release 33.1.2 + +Release 33.1.2 contains a bug fix and a new feature. + +The codename for Horizon 33.1.2 is https://wikipedia.org/wiki/$$Cotinus$$[_Smoketree_]. + +=== Bug + +* Update apache-commons-io (Issue https://issues.opennms.org/browse/NMS-16638[NMS-16638]) +* File name field in System Reports is not working (Issue https://issues.opennms.org/browse/NMS-16983[NMS-16983]) + +=== Story + +* Move grpc exporter to OpenNMS repository (Issue https://issues.opennms.org/browse/NMS-16991[NMS-16991]) + [[releasenotes-changelog-33.1.1]] == Release 33.1.1 diff --git a/features/api-layer/dao-common/src/test/java/org/opennms/features/apilayer/utils/MonitoredServiceMapperTest.java b/features/api-layer/dao-common/src/test/java/org/opennms/features/apilayer/utils/MonitoredServiceMapperTest.java index 7886affe230f..069055337952 100644 --- a/features/api-layer/dao-common/src/test/java/org/opennms/features/apilayer/utils/MonitoredServiceMapperTest.java +++ b/features/api-layer/dao-common/src/test/java/org/opennms/features/apilayer/utils/MonitoredServiceMapperTest.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/features/datachoices/src/test/java/org/opennms/features/datachoices/internal/usagestatistics/NMS16345Test.java b/features/datachoices/src/test/java/org/opennms/features/datachoices/internal/usagestatistics/NMS16345Test.java index 48d095e14cb8..e04179d14327 100644 --- a/features/datachoices/src/test/java/org/opennms/features/datachoices/internal/usagestatistics/NMS16345Test.java +++ b/features/datachoices/src/test/java/org/opennms/features/datachoices/internal/usagestatistics/NMS16345Test.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2016-2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2016-2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/features/grpc/exporter/pom.xml b/features/grpc/exporter/pom.xml new file mode 100644 index 000000000000..1cfd1022f20e --- /dev/null +++ b/features/grpc/exporter/pom.xml @@ -0,0 +1,156 @@ + + + 4.0.0 + + org.opennms.features + org.opennms.features.grpc + 34.0.0-SNAPSHOT + + + org.opennms.features.grpc + org.opennms.features.grpc.exporter + OpenNMS :: Features :: Grpc :: Exporter + bundle + + 0.6.1 + + + + + org.apache.felix + maven-bundle-plugin + true + + + JavaSE-1.8 + * + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + no.entur.mapstruct.spi + protobuf-spi-impl + 1.45 + + + + + -Amapstruct.suppressGeneratorTimestamp=true + -Amapstruct.suppressGeneratorVersionInfoComment=true + -Amapstruct.verbose=true + -s + ${project.build.directory}/generated-sources-${maven.build.timestamp} + + + + + org.mapstruct + mapstruct + ${mapstructVersion} + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.4 + + + test + generate-sources + + add-source + + + + ${basedir}/target/generated-sources + + + + + + + kr.motd.maven + os-maven-plugin + ${osMavenPluginVersion} + + + + detect + + initialize + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + com.google.protobuf:protoc:${protobufVersion}:exe:${os.detected.classifier} + grpc-java + io.grpc:protoc-gen-grpc-java:${grpcVersion}:exe:${os.detected.classifier} + + + + + compile + compile-custom + + + + + + + + + + + org.osgi + osgi.core + + + org.apache.karaf.shell + org.apache.karaf.shell.core + + + org.opennms.integration.api + common + + + org.opennms.integration.api + config + + + org.slf4j + slf4j-api + + + org.mapstruct + mapstruct + ${mapstructVersion} + + + javax.annotation + javax.annotation-api + ${javaxAnnotationApiVersion} + + + org.opennms.core.grpc + org.opennms.core.grpc.osgi + ${project.version} + + + com.google.protobuf + protobuf-java + ${protobufVersion} + + + diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/Callback.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/Callback.java new file mode 100644 index 000000000000..17cf3b4576f2 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/Callback.java @@ -0,0 +1,28 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter; + +public interface Callback { + + void sendInventorySnapShot(); +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/GrpcExporterClient.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/GrpcExporterClient.java new file mode 100644 index 000000000000..abf4407f1f92 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/GrpcExporterClient.java @@ -0,0 +1,213 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter; + +import com.google.protobuf.Empty; +import io.grpc.ConnectivityState; +import io.grpc.ManagedChannel; +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; +import io.grpc.stub.StreamObserver; +import org.opennms.plugin.grpc.proto.services.InventoryUpdateList; +import org.opennms.plugin.grpc.proto.services.ServiceSyncGrpc; +import org.opennms.plugin.grpc.proto.services.StateUpdateList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLException; +import java.io.File; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + + +public class GrpcExporterClient { + private static final Logger LOG = LoggerFactory.getLogger(GrpcExporterClient.class); + + public static final String FOREIGN_TYPE = "OpenNMS"; + + private final String host; + private final Integer port; + private final String tlsCertPath; + + private final boolean tlsEnabled; + private ManagedChannel channel; + + private ServiceSyncGrpc.ServiceSyncStub monitoredServiceSyncStub; + + private StreamObserver inventoryUpdateStream; + private StreamObserver stateUpdateStream; + private ScheduledExecutorService scheduler; + private final AtomicBoolean reconnecting = new AtomicBoolean(false); + private final AtomicBoolean stopped = new AtomicBoolean(false); + private Callback inventoryCallback; + + public GrpcExporterClient(final String host, + final Integer port, + final String tlsCertPath, + final boolean tlsEnabled) { + this.host = Objects.requireNonNull(host); + this.port = Objects.requireNonNull(port); + this.tlsCertPath = tlsCertPath; + this.tlsEnabled = tlsEnabled; + this.scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("grpc-exporter-connect")); + } + + public void start() throws SSLException { + final NettyChannelBuilder channelBuilder; + if (this.port > 0) { + channelBuilder = NettyChannelBuilder.forAddress(this.host, this.port) + .keepAliveWithoutCalls(true); + } else { + channelBuilder = NettyChannelBuilder.forTarget(this.host) + .keepAliveWithoutCalls(true); + } + + if (tlsEnabled && tlsCertPath != null && !tlsCertPath.isBlank()) { + channel = channelBuilder.useTransportSecurity() + .sslContext(GrpcSslContexts.forClient() + .trustManager(new File(tlsCertPath)).build()) + .build(); + LOG.info("TLS enabled with cert at {}", tlsCertPath); + } else if (tlsEnabled) { + // Use system store specified in javax.net.ssl.trustStore + channel = channelBuilder.useTransportSecurity() + .build(); + LOG.info("TLS enabled with certs from system store"); + } else { + channel = channelBuilder.usePlaintext() + .build(); + LOG.info("TLS disabled, using plain text"); + } + + this.monitoredServiceSyncStub = ServiceSyncGrpc.newStub(this.channel); + connectStreams(); + LOG.info("GrpcExporterClient started connection to {}:{}", this.host, this.port); + } + + public void stop() { + if (scheduler != null) { + scheduler.shutdownNow(); + } + if (channel != null) { + channel.shutdownNow(); + } + stopped.set(true); + LOG.info("GrpcExporterClient stopped"); + } + + public void setInventoryCallback(Callback inventoryCallback) { + this.inventoryCallback = inventoryCallback; + } + + private synchronized void initializeStreams() { + if (getChannelState().equals(ConnectivityState.READY)) { + try { + this.inventoryUpdateStream = + this.monitoredServiceSyncStub.inventoryUpdate(new LoggingAckReceiver("monitored_service_inventory_update", this)); + this.stateUpdateStream = + this.monitoredServiceSyncStub.stateUpdate(new LoggingAckReceiver("monitored_service_state_update", this)); + this.scheduler.shutdown(); + this.scheduler = null; + LOG.info("Streams initialized successfully."); + reconnecting.set(false); + // While connecting, reconnecting, send callback to inventory service. + if (inventoryCallback != null) { + inventoryCallback.sendInventorySnapShot(); + } + } catch (Exception e) { + LOG.error("Failed to initialize streams", e); + } + } else { + LOG.info("Channel state is not READY, retrying..."); + } + } + + private void connectStreams() { + // Schedule connect streams immediately and 30 secs thereafter. + scheduler.scheduleAtFixedRate(this::initializeStreams, 30, 30, TimeUnit.SECONDS); + } + + private synchronized void reconnectStreams() { + // Multiple streams may try to reconnect but should end up using one scheduler which schedules connection after a delay of 30 secs. + if (reconnecting.compareAndSet(false, true) && !stopped.get()) { + if (scheduler == null || scheduler.isShutdown()) { + scheduler = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("grpc-exporter-reconnect")); + scheduler.scheduleAtFixedRate(this::initializeStreams, 30, 30, TimeUnit.SECONDS); + } + } + } + + ConnectivityState getChannelState() { + return channel.getState(true); + } + + public void sendMonitoredServicesInventoryUpdate(final InventoryUpdateList inventoryUpdates) { + if (inventoryUpdateStream != null) { + this.inventoryUpdateStream.onNext(inventoryUpdates); + LOG.info("Sent an monitored service inventory update with {} services", inventoryUpdates.getServicesCount()); + } else { + LOG.warn("Unable to send inventory snapshot since channel is not ready yet"); + } + } + + public void sendMonitoredServicesStatusUpdate(final StateUpdateList stateUpdates) { + if (this.stateUpdateStream != null) { + this.stateUpdateStream.onNext(stateUpdates); + LOG.info("Sent an monitored service state update with {} services", stateUpdates.getUpdatesCount()); + } else { + LOG.warn("Unable to send monitored service status update since channel is not ready yet"); + } + } + + private static class LoggingAckReceiver implements StreamObserver { + + private final String type; + + private final GrpcExporterClient client; + + private LoggingAckReceiver(final String type, GrpcExporterClient client) { + this.type = Objects.requireNonNull(type); + this.client = client; + } + + @Override + public void onNext(final Empty value) { + LOG.debug("Received ACK {}", this.type); + } + + @Override + public void onError(final Throwable t) { + LOG.error("Received error {}", this.type, t); + client.reconnectStreams(); + } + + @Override + public void onCompleted() { + LOG.info("Completed {}", this.type); + client.reconnectStreams(); + } + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/InventoryService.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/InventoryService.java new file mode 100644 index 000000000000..939591dbac88 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/InventoryService.java @@ -0,0 +1,103 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter; + +import org.opennms.features.grpc.exporter.common.MonitoredServiceWithMetadata; +import org.opennms.features.grpc.exporter.mapper.MonitoredServiceMapper; +import org.opennms.integration.api.v1.dao.NodeDao; +import org.opennms.integration.api.v1.runtime.RuntimeInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +public class InventoryService { + private static final Logger LOG = LoggerFactory.getLogger(InventoryService.class); + + private final NodeDao nodeDao; + + private final RuntimeInfo runtimeInfo; + + private final GrpcExporterClient client; + + private final Duration snapshotInterval; + + private final ScheduledExecutorService scheduler; + + public InventoryService(final NodeDao nodeDao, + final RuntimeInfo runtimeInfo, + final GrpcExporterClient client, + final Duration snapshotInterval) { + this.nodeDao = Objects.requireNonNull(nodeDao); + this.runtimeInfo = Objects.requireNonNull(runtimeInfo); + this.client = Objects.requireNonNull(client); + this.snapshotInterval = Objects.requireNonNull(snapshotInterval); + this.scheduler = Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("inventory-service-snapshot-sender")); + } + + public InventoryService(final NodeDao nodeDao, + final RuntimeInfo runtimeInfo, + final GrpcExporterClient client, + final long snapshotInterval) { + this(nodeDao, runtimeInfo, client, Duration.ofSeconds(snapshotInterval)); + } + + public void start() { + // Start timer to send snapshots + this.scheduler.scheduleAtFixedRate(this::sendSnapshot, + this.snapshotInterval.getSeconds(), + this.snapshotInterval.getSeconds(), + TimeUnit.SECONDS); + // Set this callback to send snapshot for initial server connect and reconnects + this.client.setInventoryCallback(this::sendSnapshot); + } + + public void stop() { + this.scheduler.shutdown(); + } + + public void sendAddService(final MonitoredServiceWithMetadata service) { + final var inventory = MonitoredServiceMapper.INSTANCE.toInventoryUpdates(List.of(service), this.runtimeInfo, false); + this.client.sendMonitoredServicesInventoryUpdate(inventory); + } + + public void sendSnapshot() { + final var services = this.nodeDao.getNodes().stream() + .flatMap(node -> node.getIpInterfaces().stream() + .flatMap(iface -> iface.getMonitoredServices().stream() + .map(service -> new MonitoredServiceWithMetadata(node, iface, service)))) + .collect(Collectors.toList()); + + LOG.debug("Send snapshot: services={}", services.size()); + + final var inventory = MonitoredServiceMapper.INSTANCE.toInventoryUpdates(services, this.runtimeInfo, true); + this.client.sendMonitoredServicesInventoryUpdate(inventory); + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/NamedThreadFactory.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/NamedThreadFactory.java new file mode 100644 index 000000000000..2ebf1c0db976 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/NamedThreadFactory.java @@ -0,0 +1,44 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +public class NamedThreadFactory implements ThreadFactory { + + private final String namePrefix; + private final AtomicInteger threadNumber = new AtomicInteger(1); + + public NamedThreadFactory(String namePrefix) { + this.namePrefix = namePrefix; + } + + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, namePrefix + "-" + threadNumber.getAndIncrement()); + t.setDaemon(false); + return t; + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/StateService.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/StateService.java new file mode 100644 index 000000000000..61f07dba86d5 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/StateService.java @@ -0,0 +1,67 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter; + +import org.opennms.features.grpc.exporter.common.MonitoredServiceWithMetadata; +import org.opennms.features.grpc.exporter.mapper.MonitoredServiceMapper; +import org.opennms.integration.api.v1.dao.NodeDao; +import org.opennms.integration.api.v1.runtime.RuntimeInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class StateService { + private static final Logger LOG = LoggerFactory.getLogger(StateService.class); + + private final NodeDao nodeDao; + + private final RuntimeInfo runtimeInfo; + + private final GrpcExporterClient client; + + public StateService(final NodeDao nodeDao, + final RuntimeInfo runtimeInfo, + final GrpcExporterClient client) { + this.nodeDao = Objects.requireNonNull(nodeDao); + this.runtimeInfo = Objects.requireNonNull(runtimeInfo); + this.client = Objects.requireNonNull(client); + } + + public void sendState(final List services) { + final var updates = MonitoredServiceMapper.INSTANCE.toStateUpdates(services, this.runtimeInfo); + this.client.sendMonitoredServicesStatusUpdate(updates); + } + + public void sendAllState() { + final var services = this.nodeDao.getNodes().stream() + .flatMap(node -> node.getIpInterfaces().stream() + .flatMap(iface -> iface.getMonitoredServices().stream() + .map(service -> new MonitoredServiceWithMetadata(node, iface, service)))) + .collect(Collectors.toList()); + + this.sendState(services); + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/commands/InventorySnapshot.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/commands/InventorySnapshot.java new file mode 100644 index 000000000000..3931c5aab52a --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/commands/InventorySnapshot.java @@ -0,0 +1,43 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter.commands; + +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.lifecycle.Reference; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.opennms.features.grpc.exporter.InventoryService; + +@Command(scope = "opennms", name = "grpc-exporter-send-inventory-snapshot", description = "Send an inventory snapshot") +@Service +public class InventorySnapshot implements Action { + + @Reference + private InventoryService inventoryService; + + @Override + public Object execute() { + this.inventoryService.sendSnapshot(); + return null; + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/commands/State.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/commands/State.java new file mode 100644 index 000000000000..83b9dedd0660 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/commands/State.java @@ -0,0 +1,43 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter.commands; + +import org.apache.karaf.shell.api.action.Action; +import org.apache.karaf.shell.api.action.Command; +import org.apache.karaf.shell.api.action.lifecycle.Reference; +import org.apache.karaf.shell.api.action.lifecycle.Service; +import org.opennms.features.grpc.exporter.StateService; + +@Command(scope = "opennms", name = "grpc-exporter-send-state", description = "Send all current monitor service states") +@Service +public class State implements Action { + + @Reference + private StateService stateService; + + @Override + public Object execute() { + this.stateService.sendAllState(); + return null; + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/common/MonitoredServiceWithMetadata.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/common/MonitoredServiceWithMetadata.java new file mode 100644 index 000000000000..4bce6f6e57df --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/common/MonitoredServiceWithMetadata.java @@ -0,0 +1,56 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter.common; + +import org.opennms.integration.api.v1.model.IpInterface; +import org.opennms.integration.api.v1.model.MonitoredService; +import org.opennms.integration.api.v1.model.Node; + +import java.util.Objects; + +public class MonitoredServiceWithMetadata { + + private final Node node; + private final IpInterface iface; + private final MonitoredService monitoredService; + + public MonitoredServiceWithMetadata(final Node node, + final IpInterface iface, + final MonitoredService monitoredService) { + this.node = Objects.requireNonNull(node); + this.iface = Objects.requireNonNull(iface); + this.monitoredService = Objects.requireNonNull(monitoredService); + } + + public Node getNode() { + return this.node; + } + + public IpInterface getIface() { + return this.iface; + } + + public MonitoredService getMonitoredService() { + return this.monitoredService; + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/EventConstants.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/EventConstants.java new file mode 100644 index 000000000000..d71205f702b2 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/EventConstants.java @@ -0,0 +1,107 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter.events; + +// This has a copy of some of the events that deal with a service down/up. +public class EventConstants { + + /** + * The node gained service event UEI. + */ + public static final String NODE_GAINED_SERVICE_EVENT_UEI = "uei.opennms.org/nodes/nodeGainedService"; + + /** + * The node regained service event UEI. + */ + public static final String NODE_REGAINED_SERVICE_EVENT_UEI = "uei.opennms.org/nodes/nodeRegainedService"; + + /** + * The node lost service event UEI. + */ + public static final String NODE_LOST_SERVICE_EVENT_UEI = "uei.opennms.org/nodes/nodeLostService"; + + + /** + * The node down event UEI. + */ + public static final String NODE_DOWN_EVENT_UEI = "uei.opennms.org/nodes/nodeDown"; + + + /** + * The node up event UEI. + */ + public static final String NODE_UP_EVENT_UEI = "uei.opennms.org/nodes/nodeUp"; + + /** + * The interface up event UEI. + */ + public static final String INTERFACE_UP_EVENT_UEI = "uei.opennms.org/nodes/interfaceUp"; + + + /** + * The interface down event UEI. + */ + public static final String INTERFACE_DOWN_EVENT_UEI = "uei.opennms.org/nodes/interfaceDown"; + + /** + * The node gained interface event UEI. + */ + public static final String NODE_GAINED_INTERFACE_EVENT_UEI = "uei.opennms.org/nodes/nodeGainedInterface"; + + + /** + * The service deleted event UEI. + */ + public static final String SERVICE_DELETED_EVENT_UEI = "uei.opennms.org/nodes/serviceDeleted"; + + /** + * The interface deleted event UEI. + */ + public static final String INTERFACE_DELETED_EVENT_UEI = "uei.opennms.org/nodes/interfaceDeleted"; + + /** + * The node deleted event UEI. + */ + public static final String NODE_DELETED_EVENT_UEI = "uei.opennms.org/nodes/nodeDeleted"; + + /** + * The node added event UEI. + */ + public static final String NODE_ADDED_EVENT_UEI = "uei.opennms.org/nodes/nodeAdded"; + + /** + * The suspend polling service event UEI. + */ + public static final String SUSPEND_POLLING_SERVICE_EVENT_UEI = "uei.opennms.org/internal/poller/suspendPollingService"; + + /** + * The resume polling service event UEI. + */ + public static final String RESUME_POLLING_SERVICE_EVENT_UEI = "uei.opennms.org/internal/poller/resumePollingService"; + + public static final String SERVICE_RESPONSIVE_EVENT_UEI = "uei.opennms.org/nodes/serviceResponsive"; + public static final String SERVICE_UNRESPONSIVE_EVENT_UEI = "uei.opennms.org/nodes/serviceUnresponsive"; + public static final String SERVICE_UNMANAGED_EVENT_UEI = "uei.opennms.org/nodes/serviceUnmanaged"; + + public static final String INTERFACE_REPARENTED_EVENT_UEI = "uei.opennms.org/nodes/interfaceReparented"; +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/InventoryEventHandler.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/InventoryEventHandler.java new file mode 100644 index 000000000000..7db7d4866934 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/InventoryEventHandler.java @@ -0,0 +1,121 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter.events; + +import org.opennms.features.grpc.exporter.InventoryService; +import org.opennms.features.grpc.exporter.common.MonitoredServiceWithMetadata; +import org.opennms.integration.api.v1.dao.NodeDao; +import org.opennms.integration.api.v1.events.EventListener; +import org.opennms.integration.api.v1.events.EventSubscriptionService; +import org.opennms.integration.api.v1.model.InMemoryEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Objects; + +public class InventoryEventHandler implements EventListener { + private static final Logger LOG = LoggerFactory.getLogger(InventoryEventHandler.class); + + private final EventSubscriptionService eventSubscriptionService; + + private final NodeDao nodeDao; + + private final InventoryService inventoryService; + + public InventoryEventHandler(final EventSubscriptionService eventSubscriptionService, + final NodeDao nodeDao, + final InventoryService inventoryService) { + this.eventSubscriptionService = Objects.requireNonNull(eventSubscriptionService); + this.nodeDao = Objects.requireNonNull(nodeDao); + this.inventoryService = Objects.requireNonNull(inventoryService); + } + + public void start() { + this.eventSubscriptionService.addEventListener(this, List.of( + // Events related to a service + EventConstants.NODE_GAINED_SERVICE_EVENT_UEI, + EventConstants.SERVICE_DELETED_EVENT_UEI, + + //Events related to an interface + EventConstants.INTERFACE_DELETED_EVENT_UEI, + EventConstants.INTERFACE_REPARENTED_EVENT_UEI, + + //Events related to a node + EventConstants.NODE_DELETED_EVENT_UEI + )); + } + + public void stop() { + this.eventSubscriptionService.removeEventListener(this); + } + + @Override + public String getName() { + return InventoryEventHandler.class.getName(); + } + + @Override + public int getNumThreads() { + return 1; + } + + @Override + public void onEvent(final InMemoryEvent event) { + LOG.debug("Got event: {}", event); + + switch (event.getUei()) { + case EventConstants.NODE_GAINED_SERVICE_EVENT_UEI: + if (event.getNodeId() == null || event.getInterface() == null || event.getService() == null) { + return; + } + + final var node = this.nodeDao.getNodeById(event.getNodeId()); + if (node == null) { + return; + } + + final var iface = node.getInterfaceByIp(event.getInterface()).orElse(null); + if (iface == null) { + return; + } + + final var service = iface.getMonitoredService(event.getService()).orElse(null); + if (service == null) { + return; + } + + LOG.debug("New service: {}/{}/{}", node.getId(), iface.getIpAddress().getHostAddress(), service.getName()); + + this.inventoryService.sendAddService(new MonitoredServiceWithMetadata(node, iface, service)); + break; + + case EventConstants.SERVICE_DELETED_EVENT_UEI: + // There is not much we can do here for now + + default: + this.inventoryService.sendSnapshot(); + break; + } + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/StateEventHandler.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/StateEventHandler.java new file mode 100644 index 000000000000..3f7af82a2278 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/events/StateEventHandler.java @@ -0,0 +1,113 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter.events; + +import org.opennms.features.grpc.exporter.StateService; +import org.opennms.features.grpc.exporter.common.MonitoredServiceWithMetadata; +import org.opennms.integration.api.v1.dao.NodeDao; +import org.opennms.integration.api.v1.events.EventListener; +import org.opennms.integration.api.v1.events.EventSubscriptionService; +import org.opennms.integration.api.v1.model.InMemoryEvent; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class StateEventHandler implements EventListener { + private static final Logger LOG = LoggerFactory.getLogger(StateEventHandler.class); + + private final EventSubscriptionService eventSubscriptionService; + + private final NodeDao nodeDao; + + private final StateService stateService; + + public StateEventHandler(final EventSubscriptionService eventSubscriptionService, + final NodeDao nodeDao, + final StateService stateService) { + this.eventSubscriptionService = Objects.requireNonNull(eventSubscriptionService); + this.nodeDao = Objects.requireNonNull(nodeDao); + this.stateService = Objects.requireNonNull(stateService); + } + + public void start() { + this.eventSubscriptionService.addEventListener(this, List.of( + EventConstants.SERVICE_RESPONSIVE_EVENT_UEI, + EventConstants.SERVICE_UNRESPONSIVE_EVENT_UEI, + EventConstants.SERVICE_UNMANAGED_EVENT_UEI, + + EventConstants.NODE_REGAINED_SERVICE_EVENT_UEI, + EventConstants.NODE_LOST_SERVICE_EVENT_UEI, + + EventConstants.INTERFACE_UP_EVENT_UEI, + EventConstants.INTERFACE_DOWN_EVENT_UEI, + + EventConstants.NODE_UP_EVENT_UEI, + EventConstants.NODE_DOWN_EVENT_UEI + )); + } + + public void stop() { + this.eventSubscriptionService.removeEventListener(this); + } + + @Override + public String getName() { + return StateEventHandler.class.getName(); + } + + @Override + public int getNumThreads() { + return 1; + } + + @Override + public void onEvent(final InMemoryEvent event) { + LOG.debug("Got event: {}", event); + + if (event.getNodeId() == null) { + return; + } + + final var node = nodeDao.getNodeById(event.getNodeId()); + if (node == null) { + return; + } + + final var interfaces = event.getInterface() != null + ? node.getInterfaceByIp(event.getInterface()).stream() + : node.getIpInterfaces().stream(); + + final var services = interfaces + .flatMap(iface -> (event.getService() != null + ? iface.getMonitoredService(event.getService()).stream() + : iface.getMonitoredServices().stream() + ).map(service -> new MonitoredServiceWithMetadata(node, iface, service))) + .collect(Collectors.toList()); + + this.stateService.sendState(services); + } +} diff --git a/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/mapper/MonitoredServiceMapper.java b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/mapper/MonitoredServiceMapper.java new file mode 100644 index 000000000000..4f1b929de6a9 --- /dev/null +++ b/features/grpc/exporter/src/main/java/org/opennms/features/grpc/exporter/mapper/MonitoredServiceMapper.java @@ -0,0 +1,97 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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 org.opennms.features.grpc.exporter.mapper; + +import org.mapstruct.CollectionMappingStrategy; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Named; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.factory.Mappers; +import org.opennms.features.grpc.exporter.GrpcExporterClient; +import org.opennms.features.grpc.exporter.common.MonitoredServiceWithMetadata; +import org.opennms.integration.api.v1.runtime.RuntimeInfo; +import org.opennms.plugin.grpc.proto.services.InventoryUpdateList; +import org.opennms.plugin.grpc.proto.services.ServiceComponent; +import org.opennms.plugin.grpc.proto.services.StateUpdate; +import org.opennms.plugin.grpc.proto.services.StateUpdateList; + +import java.util.List; +import java.util.Map; + +@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED, + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) +public interface MonitoredServiceMapper { + MonitoredServiceMapper INSTANCE = Mappers.getMapper(MonitoredServiceMapper.class); + + @Named("foreignService") + default String foreignService(final MonitoredServiceWithMetadata service) { + return String.format("%s/%s/%s/%s", + service.getNode().getForeignSource(), + service.getNode().getForeignId(), + service.getIface().getIpAddress().getHostAddress(), + service.getMonitoredService().getName()); + } + + @Named("displayName") + default String displayName(final MonitoredServiceWithMetadata service) { + return String.format("%s %s %s", + service.getNode().getLabel(), + service.getIface().getIpAddress().getHostAddress(), + service.getMonitoredService().getName()); + } + + @Named("attributes") + default Map attributes(final MonitoredServiceWithMetadata service) { + return Map.ofEntries( + Map.entry("nodeId", Integer.toString(service.getNode().getId())), + Map.entry("nodeLabel", service.getNode().getLabel()), + Map.entry("location", service.getNode().getLocation()), + Map.entry("nodeCriteria", String.format("%s:%s", service.getNode().getForeignSource(), service.getNode().getForeignId())), + Map.entry("ipAddress", service.getIface().getIpAddress().getHostAddress()), + Map.entry("serviceName", service.getMonitoredService().getName()) + ); + } + + @Mapping(target = "foreignService", source = "service", qualifiedByName = "foreignService") + @Mapping(target = "name", source = "service", qualifiedByName = "displayName") + @Mapping(target = "healthy", source = "service.monitoredService.status") + @Mapping(target = "attributes", source = "service", qualifiedByName = "attributes") + @Mapping(target = "tags", source = "service.node.categories") + ServiceComponent toInventoryUpdate(final MonitoredServiceWithMetadata service); + + @Mapping(target = "foreignType", constant = GrpcExporterClient.FOREIGN_TYPE) + @Mapping(target = "foreignSource", source = "runtimeInfo.systemId") + @Mapping(target = "services", source = "services") + @Mapping(target = "snapshot", source = "snapshot") + InventoryUpdateList toInventoryUpdates(final List services, final RuntimeInfo runtimeInfo, final boolean snapshot); + + @Mapping(target = "foreignService", source = "service", qualifiedByName = "foreignService") + @Mapping(target = "healthy", source = "service.monitoredService.status") + StateUpdate toStateUpdate(final MonitoredServiceWithMetadata service); + + @Mapping(target = "foreignType", constant = GrpcExporterClient.FOREIGN_TYPE) + @Mapping(target = "foreignSource", source = "runtimeInfo.systemId") + @Mapping(target = "updates", source = "updates") + StateUpdateList toStateUpdates(final List updates, final RuntimeInfo runtimeInfo); +} diff --git a/features/grpc/exporter/src/main/proto/monitored-services.proto b/features/grpc/exporter/src/main/proto/monitored-services.proto new file mode 100644 index 000000000000..931f127a2c1f --- /dev/null +++ b/features/grpc/exporter/src/main/proto/monitored-services.proto @@ -0,0 +1,68 @@ +/* + * Licensed to The OpenNMS Group, Inc (TOG) under one or more + * contributor license agreements. See the LICENSE.md file + * distributed with this work for additional information + * regarding copyright ownership. + * + * TOG licenses this file to You under the GNU Affero General + * Public License Version 3 (the "License") or (at your option) + * any later version. You may not use this file except in + * compliance with the License. You may obtain a copy of the + * License at: + * + * https://www.gnu.org/licenses/agpl-3.0.txt + * + * 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. + */ + +syntax = "proto3"; + +import "google/protobuf/empty.proto"; + +package org.opennms.plugin.grpc.proto.services; + +option java_multiple_files = true; +option java_package = "org.opennms.plugin.grpc.proto.services"; + +message ServiceComponent { + string foreign_service = 1; + + string name = 2; + + bool healthy = 3; + + map attributes = 4; + repeated string tags = 5; +} + +message InventoryUpdateList { + string foreign_type = 1; + string foreign_source = 2; + + bool snapshot = 3; + + repeated ServiceComponent services = 4; +} + +message StateUpdate { + string foreign_service = 1; + + bool healthy = 2; +} + +message StateUpdateList { + string foreign_type = 1; + string foreign_source = 2; + + repeated StateUpdate updates = 3; +} + +service ServiceSync { + rpc InventoryUpdate(stream InventoryUpdateList) returns (stream google.protobuf.Empty) {} + rpc StateUpdate(stream StateUpdateList) returns (stream google.protobuf.Empty) {} +} diff --git a/features/grpc/exporter/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/features/grpc/exporter/src/main/resources/OSGI-INF/blueprint/blueprint.xml new file mode 100644 index 000000000000..cc32c85d2858 --- /dev/null +++ b/features/grpc/exporter/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/features/grpc/pom.xml b/features/grpc/pom.xml new file mode 100644 index 000000000000..bc227b3fc16d --- /dev/null +++ b/features/grpc/pom.xml @@ -0,0 +1,20 @@ + + + 4.0.0 + + org.opennms + org.opennms.features + 34.0.0-SNAPSHOT + + + org.opennms.features + org.opennms.features.grpc + pom + OpenNMS :: Features :: Grpc + + + exporter + + diff --git a/features/poller/monitors/core/src/main/java/org/opennms/netmgt/poller/monitors/PtpMonitor.java b/features/poller/monitors/core/src/main/java/org/opennms/netmgt/poller/monitors/PtpMonitor.java index 795f07077b34..2e57764a0249 100644 --- a/features/poller/monitors/core/src/main/java/org/opennms/netmgt/poller/monitors/PtpMonitor.java +++ b/features/poller/monitors/core/src/main/java/org/opennms/netmgt/poller/monitors/PtpMonitor.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/features/poller/monitors/core/src/test/java/org/opennms/netmgt/poller/monitors/PtpMonitorTest.java b/features/poller/monitors/core/src/test/java/org/opennms/netmgt/poller/monitors/PtpMonitorTest.java index 29cbca4557aa..996dc7b54c97 100644 --- a/features/poller/monitors/core/src/test/java/org/opennms/netmgt/poller/monitors/PtpMonitorTest.java +++ b/features/poller/monitors/core/src/test/java/org/opennms/netmgt/poller/monitors/PtpMonitorTest.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/features/pom.xml b/features/pom.xml index 7d27831765e3..89ffd007e182 100644 --- a/features/pom.xml +++ b/features/pom.xml @@ -191,5 +191,7 @@ usageanalytics inmemory-timeseries-plugin + + grpc diff --git a/features/springframework-security/src/test/java/org/opennms/web/springframework/security/NMS16450Test.java b/features/springframework-security/src/test/java/org/opennms/web/springframework/security/NMS16450Test.java index 2bc1ca49c990..44f46aac7802 100644 --- a/features/springframework-security/src/test/java/org/opennms/web/springframework/security/NMS16450Test.java +++ b/features/springframework-security/src/test/java/org/opennms/web/springframework/security/NMS16450Test.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/features/telemetry/protocols/openconfig/adapter/src/test/resources/openconfig-gnmi-telemetry.groovy b/features/telemetry/protocols/openconfig/adapter/src/test/resources/openconfig-gnmi-telemetry.groovy index 38c73ec4866a..466e8221fe18 100644 --- a/features/telemetry/protocols/openconfig/adapter/src/test/resources/openconfig-gnmi-telemetry.groovy +++ b/features/telemetry/protocols/openconfig/adapter/src/test/resources/openconfig-gnmi-telemetry.groovy @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/features/vaadin-snmp-events-and-metrics/src/test/java/org/opennms/features/vaadin/mibcompiler/NMS16444Test.java b/features/vaadin-snmp-events-and-metrics/src/test/java/org/opennms/features/vaadin/mibcompiler/NMS16444Test.java index e9dcc6437241..426593357bab 100644 --- a/features/vaadin-snmp-events-and-metrics/src/test/java/org/opennms/features/vaadin/mibcompiler/NMS16444Test.java +++ b/features/vaadin-snmp-events-and-metrics/src/test/java/org/opennms/features/vaadin/mibcompiler/NMS16444Test.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/opennms-assemblies/minion/src/main/filtered/debian/changelog b/opennms-assemblies/minion/src/main/filtered/debian/changelog index 7d7cacd9289f..4c3bd073125a 100644 --- a/opennms-assemblies/minion/src/main/filtered/debian/changelog +++ b/opennms-assemblies/minion/src/main/filtered/debian/changelog @@ -1,3 +1,12 @@ +opennms-minion (33.1.2-1) stable; urgency=medium + + * Release 33.1.2 contains a bug fix and a new feature. + + For details on what has changed, see: + https://docs.opennms.com/horizon/33.1.2/index.html + + -- OpenNMS Release Manager Tue, 07 Jan 2024 10:30:00 -0500 + opennms-minion (33.1.1-1) stable; urgency=medium * Release 33.1.1 contains bug fixes, security updates and new features. diff --git a/opennms-assemblies/sentinel/src/main/filtered/debian/changelog b/opennms-assemblies/sentinel/src/main/filtered/debian/changelog index abea928e995f..f5f6d3c7def9 100644 --- a/opennms-assemblies/sentinel/src/main/filtered/debian/changelog +++ b/opennms-assemblies/sentinel/src/main/filtered/debian/changelog @@ -1,3 +1,12 @@ +opennms-sentinel (33.1.2-1) stable; urgency=medium + + * Release 33.1.2 contains a bug fix and a new feature. + + For details on what has changed, see: + https://docs.opennms.com/horizon/33.1.2/index.html + + -- OpenNMS Release Manager Tue, 07 Jan 2024 10:30:00 -0500 + opennms-sentinel (33.1.1-1) stable; urgency=medium * Release 33.1.1 contains bug fixes, security updates and new features. diff --git a/opennms-base-assembly/src/main/filtered/etc/snmp-graph.properties.d/wsman-microsoft-windows-virtmem.properties b/opennms-base-assembly/src/main/filtered/etc/snmp-graph.properties.d/wsman-microsoft-windows-virtmem.properties deleted file mode 100644 index 9f2c81baacfa..000000000000 --- a/opennms-base-assembly/src/main/filtered/etc/snmp-graph.properties.d/wsman-microsoft-windows-virtmem.properties +++ /dev/null @@ -1,32 +0,0 @@ -############################################################################## -## -## Please add report definition in a new line to make it easier -## for script based sanity checks -## -################################################## - -reports=microsoft.windows.virtmem1 - -report.microsoft.windows.virtmem1.name=Virtual Memory -report.microsoft.windows.virtmem1.columns=freeVirtMem,totalVirtMem -report.microsoft.windows.virtmem1.type=nodeSnmp -report.microsoft.windows.virtmem1.suppress=microsoft.windows.virtmem -report.microsoft.windows.virtmem1.command=--title="Virtual Memory Usage (WinRM)" \ - --vertical-label="Memory" \ - DEF:freekBytes={rrd1}:freeVirtMem:AVERAGE \ - DEF:totalkBytes={rrd2}:totalVirtMem:AVERAGE \ - CDEF:freeBytes=freekBytes,1024,* \ - CDEF:totalBytes=totalkBytes,1024,* \ - CDEF:usedBytes=totalBytes,freeBytes,- \ - AREA:usedBytes#ff0000:"Used" \ - GPRINT:usedBytes:AVERAGE:"Avg \\: %10.2lf %s" \ - GPRINT:usedBytes:MIN:"Min \\: %10.2lf %s" \ - GPRINT:usedBytes:MAX:"Max \\: %10.2lf %s\\n" \ - STACK:freeBytes#0cff00:"Free" \ - GPRINT:freeBytes:AVERAGE:"Avg \\: %10.2lf %s" \ - GPRINT:freeBytes:MIN:"Min \\: %10.2lf %s" \ - GPRINT:freeBytes:MAX:"Max \\: %10.2lf %s\\n" \ - LINE2:totalBytes#0000ff:"Total" \ - GPRINT:totalBytes:AVERAGE:"Avg \\: %10.2lf %s" \ - GPRINT:totalBytes:MIN:"Min \\: %10.2lf %s" \ - GPRINT:totalBytes:MAX:"Max \\: %10.2lf %s\\n" diff --git a/opennms-base-assembly/src/main/filtered/etc/snmp-graph.properties.d/wsman-microsoft-windows.properties b/opennms-base-assembly/src/main/filtered/etc/snmp-graph.properties.d/wsman-microsoft-windows.properties index afa80ac0f4b8..34e4238931cb 100644 --- a/opennms-base-assembly/src/main/filtered/etc/snmp-graph.properties.d/wsman-microsoft-windows.properties +++ b/opennms-base-assembly/src/main/filtered/etc/snmp-graph.properties.d/wsman-microsoft-windows.properties @@ -10,23 +10,22 @@ reports=microsoft.windows.virtmem report.microsoft.windows.virtmem.name=Virtual Memory report.microsoft.windows.virtmem.columns=freeVirtMem,totalVirtMem report.microsoft.windows.virtmem.type=nodeSnmp -report.microsoft.windows.virtmem.command=--title="Virtual Memory Usage" \ +report.microsoft.windows.virtmem.command=--title="Virtual Memory Usage (WinRM)" \ --vertical-label="Memory" \ - DEF:freeBytes={rrd1}:freeVirtMem:AVERAGE \ - DEF:totalBytes={rrd2}:totalVirtMem:AVERAGE \ - CDEF:freeBits=freeBytes,8,* \ - CDEF:totalBits=totalBytes,8,* \ - CDEF:usedBits=totalBits,freeBits,- \ - AREA:usedBits#ff0000:"Used" \ - GPRINT:usedBits:AVERAGE:"Avg \\: %10.2lf %s" \ - GPRINT:usedBits:MIN:"Min \\: %10.2lf %s" \ - GPRINT:usedBits:MAX:"Max \\: %10.2lf %s\\n" \ - STACK:freeBits#0cff00:"Free" \ - GPRINT:freeBits:AVERAGE:"Avg \\: %10.2lf %s" \ - GPRINT:freeBits:MIN:"Min \\: %10.2lf %s" \ - GPRINT:freeBits:MAX:"Max \\: %10.2lf %s\\n" \ - LINE2:totalBits#0000ff:"Total" \ - GPRINT:totalBits:AVERAGE:"Avg \\: %10.2lf %s" \ - GPRINT:totalBits:MIN:"Min \\: %10.2lf %s" \ - GPRINT:totalBits:MAX:"Max \\: %10.2lf %s\\n" - + DEF:freekBytes={rrd1}:freeVirtMem:AVERAGE \ + DEF:totalkBytes={rrd2}:totalVirtMem:AVERAGE \ + CDEF:freeBytes=freekBytes,1024,* \ + CDEF:totalBytes=totalkBytes,1024,* \ + CDEF:usedBytes=totalBytes,freeBytes,- \ + AREA:usedBytes#ff0000:"Used" \ + GPRINT:usedBytes:AVERAGE:"Avg \\: %10.2lf %s" \ + GPRINT:usedBytes:MIN:"Min \\: %10.2lf %s" \ + GPRINT:usedBytes:MAX:"Max \\: %10.2lf %s\\n" \ + STACK:freeBytes#0cff00:"Free" \ + GPRINT:freeBytes:AVERAGE:"Avg \\: %10.2lf %s" \ + GPRINT:freeBytes:MIN:"Min \\: %10.2lf %s" \ + GPRINT:freeBytes:MAX:"Max \\: %10.2lf %s\\n" \ + LINE2:totalBytes#0000ff:"Total" \ + GPRINT:totalBytes:AVERAGE:"Avg \\: %10.2lf %s" \ + GPRINT:totalBytes:MIN:"Min \\: %10.2lf %s" \ + GPRINT:totalBytes:MAX:"Max \\: %10.2lf %s\\n" diff --git a/opennms-container/common.mk b/opennms-container/common.mk index 67c6c8a106c3..364c2260ddb5 100644 --- a/opennms-container/common.mk +++ b/opennms-container/common.mk @@ -12,7 +12,7 @@ endif VERSION := $(shell ../../.circleci/scripts/pom2version.sh ../../pom.xml) SHELL := /bin/bash -o nounset -o pipefail -o errexit BUILD_DATE := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") -BASE_IMAGE := opennms/deploy-base:ubi9-3.5.1.b280-jre-17 +BASE_IMAGE := opennms/deploy-base:ubi9-3.5.2.b283-jre-17 DOCKER_CLI_EXPERIMENTAL := enabled DOCKER_REGISTRY := docker.io DOCKER_ORG := opennms diff --git a/opennms-container/core/Dockerfile b/opennms-container/core/Dockerfile index 7a48ed8c1457..40eccc4c0351 100644 --- a/opennms-container/core/Dockerfile +++ b/opennms-container/core/Dockerfile @@ -23,7 +23,7 @@ ## # Use Java base image and setup required RPMs as cacheable image. ## -ARG BASE_IMAGE="opennms/deploy-base:ubi9-3.5.1.b280-jre-17" +ARG BASE_IMAGE="opennms/deploy-base:ubi9-3.5.2.b283-jre-17" FROM ${BASE_IMAGE} as core-tarball diff --git a/opennms-container/minion/Dockerfile b/opennms-container/minion/Dockerfile index 45dda8628887..5d1c6f1a4274 100644 --- a/opennms-container/minion/Dockerfile +++ b/opennms-container/minion/Dockerfile @@ -26,7 +26,7 @@ # To avoid issues, we rearrange the directories in pre-stage to avoid injecting these # as additional layers into the final image. ## -ARG BASE_IMAGE="opennms/deploy-base:ubi9-3.5.1.b280-jre-17" +ARG BASE_IMAGE="opennms/deploy-base:ubi9-3.5.2.b283-jre-17" FROM ${BASE_IMAGE} as minion-base diff --git a/opennms-container/sentinel/Dockerfile b/opennms-container/sentinel/Dockerfile index e4f91f669e7d..797780ad8f9e 100644 --- a/opennms-container/sentinel/Dockerfile +++ b/opennms-container/sentinel/Dockerfile @@ -23,7 +23,7 @@ ## # Use Java base image and setup required RPMs as cacheable image. ## -ARG BASE_IMAGE="opennms/deploy-base:ubi9-3.5.1.b280-jre-17" +ARG BASE_IMAGE="opennms/deploy-base:ubi9-3.5.2.b283-jre-17" FROM ${BASE_IMAGE} as sentinel-tarball diff --git a/opennms-full-assembly/pom.xml b/opennms-full-assembly/pom.xml index 655419206c1c..f0431c6cdb14 100644 --- a/opennms-full-assembly/pom.xml +++ b/opennms-full-assembly/pom.xml @@ -391,6 +391,7 @@ opennms-javamail opennms-kafka-producer opennms-kafka-consumer + opennms-grpc-exporter opennms-model opennms-measurements-shell opennms-notifications-shell diff --git a/opennms-provision/opennms-provision-persistence/src/test/java/org/opennms/netmgt/provision/persist/NMS16357Test.java b/opennms-provision/opennms-provision-persistence/src/test/java/org/opennms/netmgt/provision/persist/NMS16357Test.java index d5331c7167d3..cd2a94d02bf0 100644 --- a/opennms-provision/opennms-provision-persistence/src/test/java/org/opennms/netmgt/provision/persist/NMS16357Test.java +++ b/opennms-provision/opennms-provision-persistence/src/test/java/org/opennms/netmgt/provision/persist/NMS16357Test.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/opennms-services/src/test/java/org/opennms/netmgt/collectd/SnmpSetIT.java b/opennms-services/src/test/java/org/opennms/netmgt/collectd/SnmpSetIT.java index 1b2ed1497b96..889da9044747 100644 --- a/opennms-services/src/test/java/org/opennms/netmgt/collectd/SnmpSetIT.java +++ b/opennms-services/src/test/java/org/opennms/netmgt/collectd/SnmpSetIT.java @@ -1,8 +1,8 @@ /******************************************************************************* * This file is part of OpenNMS(R). * - * Copyright (C) 2024 The OpenNMS Group, Inc. - * OpenNMS(R) is Copyright (C) 1999-2024 The OpenNMS Group, Inc. + * Copyright (C) 2025 The OpenNMS Group, Inc. + * OpenNMS(R) is Copyright (C) 1999-2025 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * diff --git a/opennms-webapp/src/main/webapp/includes/bootstrap-footer.jsp b/opennms-webapp/src/main/webapp/includes/bootstrap-footer.jsp index b1db60e1ae99..9712377d00ad 100644 --- a/opennms-webapp/src/main/webapp/includes/bootstrap-footer.jsp +++ b/opennms-webapp/src/main/webapp/includes/bootstrap-footer.jsp @@ -58,7 +58,7 @@