Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NMS-16489: Backport of NMS-16388 #7396

Merged
merged 5 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public interface SnmpStrategy {
SnmpValue get(SnmpAgentConfig agentConfig, SnmpObjId oid);
SnmpValue[] get(SnmpAgentConfig agentConfig, SnmpObjId[] oids);
CompletableFuture<SnmpValue[]> getAsync(SnmpAgentConfig agentConfig, SnmpObjId[] oids);

CompletableFuture<SnmpValue[]> setAsync(SnmpAgentConfig agentConfig, SnmpObjId[] oids, SnmpValue[] values);
SnmpValue getNext(SnmpAgentConfig agentConfig, SnmpObjId oid);
SnmpValue[] getNext(SnmpAgentConfig agentConfig, SnmpObjId[] oids);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ public static CompletableFuture<SnmpValue[]> getAsync(SnmpAgentConfig agentConfi
return getStrategy().getAsync(agentConfig, oids);
}

public static CompletableFuture<SnmpValue[]> setAsync(SnmpAgentConfig agentConfig, SnmpObjId[] oids, SnmpValue[] values) {
return getStrategy().setAsync(agentConfig, oids, values);
}

public static SnmpValue getNext(SnmpAgentConfig agentConfig, SnmpObjId oid) {
return getStrategy().getNext(agentConfig, oid);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@

package org.opennms.netmgt.snmp.proxy;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.opennms.netmgt.snmp.CollectionTracker;
import org.opennms.netmgt.snmp.SnmpAgentConfig;
import org.opennms.netmgt.snmp.SnmpObjId;
import org.opennms.netmgt.snmp.SnmpResult;
import org.opennms.netmgt.snmp.SnmpValue;

import com.google.common.collect.Lists;

/**
* Asynchronous SNMP client API that either executes the request locally, delegating
* the request to the current {@link org.opennms.netmgt.snmp.SnmpStrategy}, or dispatches
Expand All @@ -62,4 +66,14 @@ public interface LocationAwareSnmpClient {
SNMPRequestBuilder<List<SnmpValue>> get(SnmpAgentConfig agent, SnmpObjId... oids);

SNMPRequestBuilder<List<SnmpValue>> get(SnmpAgentConfig agent, List<SnmpObjId> oids);

SNMPRequestBuilder<SnmpValue> set(SnmpAgentConfig agent, List<SnmpObjId> oids, List<SnmpValue> values);

default SNMPRequestBuilder<SnmpValue> set(SnmpAgentConfig agent, SnmpObjId oid, SnmpValue value) {
return set(agent, Collections.singletonList(oid), Collections.singletonList(value));
}

default SNMPRequestBuilder<SnmpValue> set(SnmpAgentConfig agent, SnmpObjId[] oids, SnmpValue[] values) {
return set(agent, Lists.newArrayList(oids), Lists.newArrayList(values));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,13 @@ public CompletableFuture<SnmpValue[]> getAsync(SnmpAgentConfig agentConfig, Snmp
return CompletableFuture.completedFuture(get(agentConfig, oids));
}

@Override
@Override
public CompletableFuture<SnmpValue[]> setAsync(SnmpAgentConfig agentConfig, SnmpObjId[] oids, SnmpValue[] values) {
LOG.warn("The JoeSnmpStrategy does not support asynchronous SNMP SET requests.");
return CompletableFuture.completedFuture(set(agentConfig, oids, values));
}

@Override
public SnmpValue getNext(SnmpAgentConfig snmpAgentConfig, SnmpObjId oid) {
SnmpObjId[] oids = { oid };
return getNext(snmpAgentConfig, oids)[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ public CompletableFuture<SnmpValue[]> getAsync(SnmpAgentConfig agentConfig, Snmp
return CompletableFuture.completedFuture(get(agentConfig, oids));
}

@Override
public CompletableFuture<SnmpValue[]> setAsync(SnmpAgentConfig agentConfig, SnmpObjId[] oids, SnmpValue[] values) {
return CompletableFuture.completedFuture(set(agentConfig, oids, values));
}

@Override
public SnmpValue getNext(final SnmpAgentConfig agentConfig, final SnmpObjId oid) {
final PropertyOidContainer oidContainer = getOidContainer(agentConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ public String getVersionString() {
}
}

public String getWriteCommunity() {
return m_config.getWriteCommunity();
public OctetString getWriteCommunity() {
return convertCommunity(m_config.getWriteCommunity());
}

@Override
Expand Down Expand Up @@ -267,27 +267,31 @@ private static OID convertAuthProtocol(String authProtocol) {

@VisibleForTesting
public Target getTarget() {
Target target = createTarget();
return getTarget(false);
}

public Target getTarget(final boolean useWriteCommunity) {
Target target = createTarget(useWriteCommunity);
target.setVersion(getVersion());
target.setRetries(getRetries());
target.setTimeout(getTimeout());
target.setAddress(getAddress());
target.setMaxSizeRequestPDU(getMaxRequestSize());

return target;
}

private Target createTarget() {
return (isSnmpV3() ? createUserTarget() : createCommunityTarget());
private Target createTarget(final boolean useWriteCommunity) {
return (isSnmpV3() ? createUserTarget() : createCommunityTarget(useWriteCommunity));
}

boolean isSnmpV3() {
return m_config.getVersion() == SnmpConstants.version3;
}

private Target createCommunityTarget() {
private Target createCommunityTarget(final boolean useWriteCommunity) {
CommunityTarget target = new CommunityTarget();
target.setCommunity(getReadCommunity());
target.setCommunity(useWriteCommunity ? getWriteCommunity() : getReadCommunity());
return target;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,18 @@ public CompletableFuture<SnmpValue[]> getAsync(SnmpAgentConfig agentConfig, Snmp
return future;
}

@Override
public CompletableFuture<SnmpValue[]> setAsync(SnmpAgentConfig agentConfig, SnmpObjId[] oids, SnmpValue[] values) {
final CompletableFuture<SnmpValue[]> future = new CompletableFuture<>();
final Snmp4JAgentConfig snmp4jAgentConfig = new Snmp4JAgentConfig(agentConfig);
final PDU pdu = buildPdu(snmp4jAgentConfig, PDU.SET, oids, values);
if (pdu == null) {
future.completeExceptionally(new Exception("Invalid PDU for OIDs: " + Arrays.toString(oids)));
}
send(snmp4jAgentConfig, pdu, true, future);
return future;
}

/**
* SNMP4J getNext implementation
*
Expand Down Expand Up @@ -352,7 +364,7 @@ private void send(Snmp4JAgentConfig agentConfig, PDU pdu, boolean expectResponse

try {
final Snmp mySession = session;
mySession.send(pdu, agentConfig.getTarget(), null, new ResponseListener() {
mySession.send(pdu, agentConfig.getTarget(pdu.getType() == PDU.SET), null, new ResponseListener() {
@Override
public void onResponse(final ResponseEvent responseEvent) {
try {
Expand Down Expand Up @@ -381,7 +393,7 @@ public void run() {
}
} else { // we're not expecting a response
try {
session.send(pdu, agentConfig.getTarget());
session.send(pdu, agentConfig.getTarget(pdu.getType() == PDU.SET));
future.complete(null);
} catch (final Exception e) {
LOG.error("send: error during SNMP operation", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,19 @@ public abstract class AbstractSNMPRequestBuilder<T> implements SNMPRequestBuilde
private final SnmpAgentConfig agent;
private List<SnmpGetRequestDTO> gets;
private List<SnmpWalkRequestDTO> walks;
private List<SnmpSetRequestDTO> sets;
private String location;
private String systemId;
private String description;
private Long timeToLiveInMilliseconds = null;

public AbstractSNMPRequestBuilder(LocationAwareSnmpClientRpcImpl client,
SnmpAgentConfig agent, List<SnmpGetRequestDTO> gets, List<SnmpWalkRequestDTO> walks) {
SnmpAgentConfig agent, List<SnmpGetRequestDTO> gets, List<SnmpWalkRequestDTO> walks, List<SnmpSetRequestDTO> sets) {
this.client = Objects.requireNonNull(client);
this.agent = Objects.requireNonNull(agent);
this.gets = Objects.requireNonNull(gets);
this.walks = Objects.requireNonNull(walks);
this.sets = Objects.requireNonNull(sets);
}

@Override
Expand Down Expand Up @@ -96,6 +98,7 @@ public CompletableFuture<T> execute() {
snmpRequestDTO.setDescription(description);
snmpRequestDTO.setGetRequests(gets);
snmpRequestDTO.setWalkRequests(walks);
snmpRequestDTO.setSetRequests(sets);
// TTL specified in agent configuration overwrites any previous ttls specified.
if (agent.getTTL() != null) {
timeToLiveInMilliseconds = agent.getTTL();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -122,6 +123,11 @@ public SNMPRequestBuilder<List<SnmpValue>> get(SnmpAgentConfig agent, List<SnmpO
return new SNMPMultiGetBuilder(this, agent, oids);
}

@Override
public SNMPRequestBuilder<SnmpValue> set(SnmpAgentConfig agent, List<SnmpObjId> oids, List<SnmpValue> values) {
return new SNMPSetBuilder(this, agent, oids, values);
}

public CompletableFuture<SnmpMultiResponseDTO> execute(SnmpRequestDTO request) {
return delegate.execute(request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
public class SNMPMultiGetBuilder extends AbstractSNMPRequestBuilder<List<SnmpValue>> {

public SNMPMultiGetBuilder(LocationAwareSnmpClientRpcImpl client, SnmpAgentConfig agent, List<SnmpObjId> oids) {
super(client, agent, buildGetRequests(oids), Collections.emptyList());
super(client, agent, buildGetRequests(oids), Collections.emptyList(), Collections.emptyList());
}

private static List<SnmpGetRequestDTO> buildGetRequests(List<SnmpObjId> oids) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*******************************************************************************
* 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.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/

package org.opennms.netmgt.snmp.proxy.common;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.opennms.netmgt.snmp.SnmpAgentConfig;
import org.opennms.netmgt.snmp.SnmpObjId;
import org.opennms.netmgt.snmp.SnmpResult;
import org.opennms.netmgt.snmp.SnmpValue;

public class SNMPSetBuilder extends AbstractSNMPRequestBuilder<SnmpValue> {

public SNMPSetBuilder(LocationAwareSnmpClientRpcImpl client, SnmpAgentConfig agent, List<SnmpObjId> oids, List<SnmpValue> values) {
super(client, agent, Collections.emptyList(), Collections.emptyList(), buildGetRequests(oids, values));
}

private static List<SnmpSetRequestDTO> buildGetRequests(List<SnmpObjId> oids, List<SnmpValue> values) {
final SnmpSetRequestDTO setRequest = new SnmpSetRequestDTO();
setRequest.setOids(oids);
setRequest.setValues(values);
return Collections.singletonList(setRequest);
}

@Override
protected SnmpValue processResponse(SnmpMultiResponseDTO response) {
return response.getResponses().stream()
.flatMap(res -> res.getResults().stream())
.findFirst()
.map(SnmpResult::getValue)
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
public class SNMPSingleGetBuilder extends AbstractSNMPRequestBuilder<SnmpValue> {

public SNMPSingleGetBuilder(LocationAwareSnmpClientRpcImpl client, SnmpAgentConfig agent, SnmpObjId oid) {
super(client, agent, buildGetRequests(oid), Collections.emptyList());
super(client, agent, buildGetRequests(oid), Collections.emptyList(), Collections.emptyList());
}

private static List<SnmpGetRequestDTO> buildGetRequests(SnmpObjId oid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
public class SNMPWalkBuilder extends AbstractSNMPRequestBuilder<List<SnmpResult>> {

public SNMPWalkBuilder(LocationAwareSnmpClientRpcImpl client, SnmpAgentConfig agent, List<SnmpObjId> oids) {
super(client, agent, Collections.emptyList(), buildWalkRequests(oids));
super(client, agent, Collections.emptyList(), buildWalkRequests(oids), Collections.emptyList());
}

private static List<SnmpWalkRequestDTO> buildWalkRequests(List<SnmpObjId> oids) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class SNMPWalkWithTrackerBuilder extends AbstractSNMPRequestBuilder<Colle
private final CollectionTracker m_tracker;

public SNMPWalkWithTrackerBuilder(LocationAwareSnmpClientRpcImpl client, SnmpAgentConfig agent, CollectionTracker tracker) {
super(client, agent, Collections.emptyList(), buildWalkRequests(tracker));
super(client, agent, Collections.emptyList(), buildWalkRequests(tracker), Collections.emptyList());
m_tracker = tracker;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ public CompletableFuture<SnmpMultiResponseDTO> execute(SnmpRequestDTO request) {
return m;
});
}
for (SnmpSetRequestDTO setRequest : request.getSetRequest()) {
CompletableFuture<SnmpResponseDTO> future = set(request, setRequest);
combinedFuture = combinedFuture.thenCombine(future, (m, s) -> {
m.getResponses().add(s);
return m;
});
}
if (request.getWalkRequest().size() > 0) {
CompletableFuture<Collection<SnmpResponseDTO>> future = walk(request, request.getWalkRequest());
combinedFuture = combinedFuture.thenCombine(future, (m, s) -> {
Expand Down Expand Up @@ -211,6 +218,30 @@ private CompletableFuture<SnmpResponseDTO> get(SnmpRequestDTO request, SnmpGetRe
});
}

private CompletableFuture<SnmpResponseDTO> set(SnmpRequestDTO request, SnmpSetRequestDTO get) {
final SnmpObjId[] oids = get.getOids().toArray(new SnmpObjId[0]);
final SnmpValue[] value = get.getValues().toArray(new SnmpValue[0]);
final CompletableFuture<SnmpValue[]> future = SnmpUtils.setAsync(request.getAgent(), oids, value);
return future.thenApply(values -> {
final List<SnmpResult> results = new ArrayList<>(oids.length);
if (values.length < oids.length) {
// Should never reach here, should have thrown exception in SnmpUtils.
LOG.warn("Received error response from SNMP for the agent {} for oids = {}", request.getAgent(), oids);
final SnmpResponseDTO responseDTO = new SnmpResponseDTO();
responseDTO.setCorrelationId(get.getCorrelationId());
} else {
for (int i = 0; i < oids.length; i++) {
final SnmpResult result = new SnmpResult(oids[i], null, values[i]);
results.add(result);
}
}
final SnmpResponseDTO responseDTO = new SnmpResponseDTO();
responseDTO.setCorrelationId(get.getCorrelationId());
responseDTO.setResults(results);
return responseDTO;
});
}

@Override
public SnmpMultiResponseDTO createResponseWithException(Throwable ex) {
return new SnmpMultiResponseDTO(ex);
Expand Down
Loading
Loading