NETCONF-542: PUT request return 500 if operational data are used 89/71989/8
authormiroslav.kovac <miroslav.kovac@pantheon.tech>
Mon, 14 May 2018 08:34:11 +0000 (10:34 +0200)
committerMiroslav Kovac <miroslav.kovac@pantheon.tech>
Tue, 29 May 2018 12:11:59 +0000 (12:11 +0000)
Change-Id: I5e45b0276e39c3a6af647b6632b67b3f96751464
Signed-off-by: miroslav.kovac <miroslav.kovac@pantheon.tech>
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/netconf/sal/tx/AbstractWriteTx.java
restconf/restconf-nb-rfc8040/pom.xml
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/FutureCallbackTx.java

index 8c5929752c97bf0ea056a41aea4165c3600808ac..0ed0a6171e9c994b04a966e1fac57cfad3f1ac91 100644 (file)
@@ -192,19 +192,8 @@ public abstract class AbstractWriteTx implements DOMDataWriteTransaction {
         Futures.addCallback(Futures.allAsList(resultsFutures), new FutureCallback<List<DOMRpcResult>>() {
             @Override
             public void onSuccess(final List<DOMRpcResult> 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(TransactionStatus.COMMITED).build());
+                    extractResult(domRpcResults, transformed);
                 }
             }
 
@@ -224,6 +213,61 @@ public abstract class AbstractWriteTx implements DOMDataWriteTransaction {
         return transformed;
     }
 
+    private void extractResult(final List<DOMRpcResult> domRpcResults,
+                               final SettableFuture<RpcResult<TransactionStatus>> 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(TransactionStatus.COMMITED).build());
+    }
+
     AutoCloseable addListener(final TxListener listener) {
         listeners.add(listener);
         return () -> listeners.remove(listener);
index 27ad7acda419e829b32132f8dda9d9db193b0fed..cd0120386e57075e447a43eae854e73d3cc118b4 100644 (file)
@@ -26,7 +26,7 @@
     <dependencies>
       <dependency>
         <groupId>org.opendaylight.netconf</groupId>
-        <artifactId>netconf-parent</artifactId>
+        <artifactId>netconf-artifacts</artifactId>
         <version>1.4.2-SNAPSHOT</version>
         <type>pom</type>
         <scope>import</scope>
       <artifactId>ietf-yang-library</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>netconf-api</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
index 4969942ac46955f41d769671c8eee6af04b1288a..447836260bca9a607f8c2524e854e1a3321ada2c 100644 (file)
@@ -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<Throwable> 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);
             }
         }
     }