X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fmdsal-netconf-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fmdsal%2Fconnector%2Fops%2FEditConfig.java;h=fbefb5c56d818ffd3e039cea449202530a113e42;hp=09be4163df8ad8d5247fd23e64f34a5b4e0c5b16;hb=a681e6bec3bbd7b536302ee9e083ae04b7f5ebdd;hpb=3997099eb61b0f2adc47f7a85952c324e9de223f diff --git a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java index 09be4163df..fbefb5c56d 100644 --- a/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java +++ b/opendaylight/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/controller/netconf/mdsal/connector/ops/EditConfig.java @@ -23,9 +23,12 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException.ErrorT import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants; import org.opendaylight.controller.netconf.mdsal.connector.CurrentSchemaContext; import org.opendaylight.controller.netconf.mdsal.connector.TransactionProvider; -import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation; +import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException; +import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException; +import org.opendaylight.controller.netconf.util.mapping.AbstractSingletonNetconfOperation; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.opendaylight.yangtools.yang.data.api.ModifyAction; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.MapNode; @@ -45,12 +48,15 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; -public class EditConfig extends AbstractLastNetconfOperation { +public class EditConfig extends AbstractSingletonNetconfOperation { private static final Logger LOG = LoggerFactory.getLogger(EditConfig.class); private static final String OPERATION_NAME = "edit-config"; private static final String CONFIG_KEY = "config"; + private static final String TARGET_KEY = "target"; + private static final String DEFAULT_OPERATION_KEY = "default-operation"; + private final CurrentSchemaContext schemaContext; private final TransactionProvider transactionProvider; @@ -63,7 +69,17 @@ public class EditConfig extends AbstractLastNetconfOperation { @Override protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException { - final XmlElement configElement = getConfigElement(operationElement); + final Datastore targetDatastore = extractTargetParameter(operationElement); + if (targetDatastore == Datastore.running) { + throw new NetconfDocumentedException("edit-config on running datastore is not supported", + ErrorType.protocol, + ErrorTag.operation_not_supported, + ErrorSeverity.error); + } + + final ModifyAction defaultAction = getDefaultOperation(operationElement); + + final XmlElement configElement = getElement(operationElement, CONFIG_KEY); for (XmlElement element : configElement.getChildElements()) { final String ns = element.getNamespace(); @@ -72,22 +88,19 @@ public class EditConfig extends AbstractLastNetconfOperation { final NormalizedNode storedNode = readStoredNode(LogicalDatastoreType.CONFIGURATION, ident); try { - final Optional> newNode = modifyNode(schemaNode, element, storedNode); + final Optional> newNode = modifyNode(schemaNode, element, storedNode, defaultAction); final DOMDataReadWriteTransaction rwTx = transactionProvider.getOrCreateTransaction(); if (newNode.isPresent()) { rwTx.put(LogicalDatastoreType.CONFIGURATION, ident, newNode.get()); } else { rwTx.delete(LogicalDatastoreType.CONFIGURATION, ident); } + } catch (final DataExistsException e) { + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_exists, ErrorSeverity.error); + } catch (final DataMissingException e) { + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_missing, ErrorSeverity.error); } catch (final DataModificationException e) { - if (e instanceof DataExistsException) { - throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_exists, ErrorSeverity.error); - } else if (e instanceof DataMissingException) { - throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.data_missing, ErrorSeverity.error); - } else { - //should never happen, since in edit-config only the 2 previous cases can happen - throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.operation_failed, ErrorSeverity.error); - } + throw new NetconfDocumentedException(e.getMessage(), e, ErrorType.protocol, ErrorTag.operation_failed, ErrorSeverity.error); } } @@ -102,23 +115,32 @@ public class EditConfig extends AbstractLastNetconfOperation { final NormalizedNode node = readFuture.checkedGet().get(); return node; } else { - LOG.warn("Unable to read node : {} from {} datastore", path, logicalDatastoreType); + LOG.debug("Unable to read node : {} from {} datastore", path, logicalDatastoreType); } } catch (final ReadFailedException e) { //only log this since DataOperations.modify will handle throwing an exception or writing the node. - LOG.warn("Unable to read stored data: {}", path, e); + LOG.debug("Unable to read stored data: {}", path, e); } //we can return null here since DataOperations.modify handles null as input return null; } - private Optional getSchemaNodeFromNamespace(final String namespace, final XmlElement element){ + private Optional getSchemaNodeFromNamespace(final String namespace, final XmlElement element) throws NetconfDocumentedException{ Optional dataSchemaNode = Optional.absent(); try { //returns module with newest revision since findModuleByNamespace returns a set of modules and we only need the newest one final Module module = schemaContext.getCurrentContext().findModuleByNamespaceAndRevision(new URI(namespace), null); - dataSchemaNode = Optional.of(module.getDataChildByName(element.getName())); + DataSchemaNode schemaNode = module.getDataChildByName(element.getName()); + if (schemaNode != null) { + dataSchemaNode = Optional.of(module.getDataChildByName(element.getName())); + } else { + throw new NetconfDocumentedException("Unable to find node with namespace: " + namespace + "in module: " + module.toString(), + ErrorType.application, + ErrorTag.unknown_namespace, + ErrorSeverity.error); + } + } catch (URISyntaxException e) { LOG.debug("Unable to create URI for namespace : {}", namespace); } @@ -126,7 +148,7 @@ public class EditConfig extends AbstractLastNetconfOperation { return dataSchemaNode; } - private Optional> modifyNode(final DataSchemaNode schemaNode, final XmlElement element, final NormalizedNode storedNode) throws DataModificationException{ + private Optional> modifyNode(final DataSchemaNode schemaNode, final XmlElement element, final NormalizedNode storedNode, final ModifyAction defaultAction) throws DataModificationException{ if (schemaNode instanceof ContainerSchemaNode) { final ContainerNode modifiedNode = DomToNormalizedNodeParserFactory @@ -134,7 +156,7 @@ public class EditConfig extends AbstractLastNetconfOperation { .getContainerNodeParser() .parse(Collections.singletonList(element.getDomElement()), (ContainerSchemaNode) schemaNode); - final Optional oNode = DataOperations.modify((ContainerSchemaNode) schemaNode, (ContainerNode) storedNode, modifiedNode); + final Optional oNode = DataOperations.modify((ContainerSchemaNode) schemaNode, (ContainerNode) storedNode, modifiedNode, defaultAction); if (!oNode.isPresent()) { return Optional.absent(); } @@ -148,7 +170,7 @@ public class EditConfig extends AbstractLastNetconfOperation { .getMapNodeParser() .parse(Collections.singletonList(element.getDomElement()), (ListSchemaNode) schemaNode); - final Optional oNode = DataOperations.modify((ListSchemaNode) schemaNode, (MapNode) storedNode, modifiedNode); + final Optional oNode = DataOperations.modify((ListSchemaNode) schemaNode, (MapNode) storedNode, modifiedNode, defaultAction); if (!oNode.isPresent()) { return Optional.absent(); } @@ -163,20 +185,49 @@ public class EditConfig extends AbstractLastNetconfOperation { } - private XmlElement getConfigElement(final XmlElement operationElement) throws NetconfDocumentedException{ - final Optional configChildNode = operationElement.getOnlyChildElementOptionally(CONFIG_KEY); - if (!configChildNode.isPresent()) { - throw new NetconfDocumentedException("Can't get child element with name: " + CONFIG_KEY, - ErrorType.application, - ErrorTag.unknown_element, + private Datastore extractTargetParameter(final XmlElement operationElement) throws NetconfDocumentedException { + final XmlElement targetChildNode; + try { + final XmlElement targetElement = operationElement.getOnlyChildElementWithSameNamespace(TARGET_KEY); + targetChildNode = targetElement.getOnlyChildElementWithSameNamespace(); + } catch (final MissingNameSpaceException | UnexpectedNamespaceException e) { + LOG.trace("Can't get only child element with same namespace", e); + throw NetconfDocumentedException.wrap(e); + } + + return Datastore.valueOf(targetChildNode.getName()); + } + + private ModifyAction getDefaultOperation(final XmlElement operationElement) throws NetconfDocumentedException{ + try { + return ModifyAction.fromXmlValue(getElement(operationElement, DEFAULT_OPERATION_KEY).getTextContent()); + } catch (NetconfDocumentedException e) { + if (e.getErrorType() == ErrorType.protocol + && e.getErrorSeverity() == ErrorSeverity.error + && e.getErrorTag() == ErrorTag.missing_element) { + return ModifyAction.MERGE; + } + else { + throw e; + } + } + } + + private XmlElement getElement(final XmlElement operationElement, String elementName) throws NetconfDocumentedException { + final Optional childNode = operationElement.getOnlyChildElementOptionally(elementName); + if (!childNode.isPresent()) { + throw new NetconfDocumentedException(elementName + " element is missing", + ErrorType.protocol, + ErrorTag.missing_element, ErrorSeverity.error); } - return configChildNode.get(); + return childNode.get(); } @Override protected String getOperationName() { return OPERATION_NAME; } + }