From bd46da04a62e5940f9a60dd4001e5cf27fca31fe Mon Sep 17 00:00:00 2001 From: "miroslav.kovac" Date: Tue, 29 May 2018 20:09:24 +0200 Subject: [PATCH] NETCONF-542: PUT request return 500 if operational data are used * Cherry-pick Change-Id: I5e45b0276e39c3a6af647b6632b67b3f96751464 Signed-off-by: miroslav.kovac --- .../netconf/sal/tx/AbstractWriteTx.java | 68 +++++++++++++++---- restconf/restconf-nb-rfc8040/pom.xml | 10 ++- .../rfc8040/rests/utils/FutureCallbackTx.java | 25 ++++++- restconf/restconf-parent/pom.xml | 7 ++ 4 files changed, 93 insertions(+), 17 deletions(-) diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/AbstractWriteTx.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/AbstractWriteTx.java index 60bf213f88..56b3dab7d9 100644 --- a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/AbstractWriteTx.java +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/AbstractWriteTx.java @@ -235,19 +235,8 @@ public abstract class AbstractWriteTx implements DOMDataWriteTransaction { Futures.addCallback(Futures.allAsList(resultsFutures), new FutureCallback>() { @Override public void onSuccess(@Nonnull final List domRpcResults) { - domRpcResults.forEach(domRpcResult -> { - if (!domRpcResult.getErrors().isEmpty() && !transformed.isDone()) { - final NetconfDocumentedException exception = - new NetconfDocumentedException(id + ":RPC during tx failed", - DocumentedException.ErrorType.APPLICATION, - DocumentedException.ErrorTag.OPERATION_FAILED, - DocumentedException.ErrorSeverity.ERROR); - transformed.setException(exception); - } - }); - if (!transformed.isDone()) { - transformed.set(RpcResultBuilder.success().build()); + extractResult(domRpcResults, transformed); } } @@ -267,6 +256,61 @@ public abstract class AbstractWriteTx implements DOMDataWriteTransaction { return transformed; } + private void extractResult(final List domRpcResults, + final SettableFuture> transformed) { + for (final DOMRpcResult domRpcResult : domRpcResults) { + if (!domRpcResult.getErrors().isEmpty()) { + final RpcError error = domRpcResult.getErrors().iterator().next(); + final RpcError.ErrorType errorType = error.getErrorType(); + final DocumentedException.ErrorType eType; + switch (errorType) { + case RPC: + eType = DocumentedException.ErrorType.RPC; + break; + case PROTOCOL: + eType = DocumentedException.ErrorType.PROTOCOL; + break; + case TRANSPORT: + eType = DocumentedException.ErrorType.TRANSPORT; + break; + case APPLICATION: + eType = DocumentedException.ErrorType.APPLICATION; + break; + default: + eType = DocumentedException.ErrorType.APPLICATION; + break; + } + final RpcError.ErrorSeverity severity = error.getSeverity(); + final DocumentedException.ErrorSeverity eSeverity; + switch (severity) { + case ERROR: + eSeverity = DocumentedException.ErrorSeverity.ERROR; + break; + case WARNING: + eSeverity = DocumentedException.ErrorSeverity.WARNING; + break; + default: + eSeverity = DocumentedException.ErrorSeverity.ERROR; + break; + } + final String message; + if (error.getMessage() == null || error.getMessage().isEmpty()) { + message = id + ":RPC during tx failed"; + } else { + message = error.getMessage(); + } + final NetconfDocumentedException exception = new NetconfDocumentedException(message, + eType, + DocumentedException.ErrorTag.from(error.getTag()), + eSeverity); + transformed.setException(exception); + return; + } + } + + transformed.set(RpcResultBuilder.success().build()); + } + AutoCloseable addListener(final TxListener listener) { listeners.add(listener); return () -> listeners.remove(listener); diff --git a/restconf/restconf-nb-rfc8040/pom.xml b/restconf/restconf-nb-rfc8040/pom.xml index 83f5629869..ac9f586a6b 100644 --- a/restconf/restconf-nb-rfc8040/pom.xml +++ b/restconf/restconf-nb-rfc8040/pom.xml @@ -26,15 +26,19 @@ org.opendaylight.netconf restconf-common-models - + org.opendaylight.netconf restconf-common - + org.opendaylight.netconf ietf-yang-library - + + + org.opendaylight.netconf + netconf-api + org.opendaylight.yangtools diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/FutureCallbackTx.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/FutureCallbackTx.java index 4969942ac4..447836260b 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/FutureCallbackTx.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/FutureCallbackTx.java @@ -7,12 +7,16 @@ */ package org.opendaylight.restconf.nb.rfc8040.rests.utils; +import com.google.common.base.Throwables; import com.google.common.util.concurrent.CheckedFuture; import java.util.ArrayList; import java.util.List; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.dom.api.DOMRpcException; import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult; +import org.opendaylight.netconf.api.NetconfDocumentedException; import org.opendaylight.restconf.common.errors.RestconfDocumentedException; +import org.opendaylight.restconf.common.errors.RestconfError; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; @@ -58,9 +62,26 @@ final class FutureCallbackTx { rpcErrorList.add( RpcResultBuilder.newError(RpcError.ErrorType.RPC, "operation-failed", e.getMessage())); dataFactory.setResult((T) new DefaultDOMRpcResult(rpcErrorList)); + } else if (e instanceof TransactionCommitFailedException) { + /* If device send some error message we want this message to get to client + and not just to throw it away or override it with new generic message. + We search for NetconfDocumentedException that was send from netconfSB + and we create RestconfDocumentedException accordingly. + */ + final List causalChain = Throwables.getCausalChain(e); + for (Throwable error : causalChain) { + if (error instanceof NetconfDocumentedException) { + throw new RestconfDocumentedException(error.getMessage(), + RestconfError.ErrorType.valueOfCaseInsensitive( + ((NetconfDocumentedException) error).getErrorType().getTypeValue()), + RestconfError.ErrorTag.valueOfCaseInsensitive( + ((NetconfDocumentedException) error).getErrorTag().getTagValue()), e); + } + } + + throw new RestconfDocumentedException("Transaction(" + txType + ") not committed correctly", e); } else { - throw new RestconfDocumentedException( - "Transaction(" + txType + ") not committed correctly", e); + throw new RestconfDocumentedException("Transaction failed", e); } } } diff --git a/restconf/restconf-parent/pom.xml b/restconf/restconf-parent/pom.xml index d1c2ac50bb..7e6a0dd9c9 100644 --- a/restconf/restconf-parent/pom.xml +++ b/restconf/restconf-parent/pom.xml @@ -36,6 +36,13 @@ pom import + + org.opendaylight.netconf + netconf-artifacts + 1.5.0-SNAPSHOT + pom + import + org.opendaylight.netconf restconf-artifacts -- 2.36.6