Implement basic locking for candidate in config-netconf-connector 37/13537/3
authorMaros Marsalek <mmarsale@cisco.com>
Wed, 10 Dec 2014 13:13:29 +0000 (14:13 +0100)
committerMaros Marsalek <mmarsale@cisco.com>
Mon, 15 Dec 2014 15:22:25 +0000 (16:22 +0100)
Change-Id: I4ec0efd7b1ac1bc33f90289d11cd28ca685e348b
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Lock.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/UnLock.java [new file with mode: 0644]
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/osgi/NetconfOperationProvider.java
opendaylight/netconf/config-netconf-connector/src/test/java/org/opendaylight/controller/netconf/confignetconfconnector/NetconfMappingTest.java
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/lock.xml [new file with mode: 0644]
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unlock.xml [new file with mode: 0644]

diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Lock.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/Lock.java
new file mode 100644 (file)
index 0000000..ea01964
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.confignetconfconnector.operations;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.exception.MissingNameSpaceException;
+import org.opendaylight.controller.netconf.util.exception.UnexpectedNamespaceException;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Simple Lock implementation that pretends to lock candidate datastore.
+ * Candidate datastore is allocated per session and is private so no real locking is needed (JMX is the only possible interference)
+ */
+public class Lock extends AbstractLastNetconfOperation {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Lock.class);
+
+    private static final String LOCK = "lock";
+    private static final String TARGET_KEY = "target";
+
+    public Lock(final String netconfSessionIdForReporting) {
+        super(netconfSessionIdForReporting);
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        final Datastore targetDatastore = extractTargetParameter(operationElement);
+        if(targetDatastore == Datastore.candidate) {
+            // Since candidate datastore instances are allocated per session and not accessible anywhere else, no need to lock
+            LOG.debug("Locking {} datastore on session: {}", targetDatastore, getNetconfSessionIdForReporting());
+            // TODO should this fail if we are already locked ?
+            return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+        }
+
+        // Not supported running lock
+        throw new NetconfDocumentedException("Unable to lock " + Datastore.running + " datastore", NetconfDocumentedException.ErrorType.application,
+                NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+    }
+
+    static 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());
+    }
+
+    @Override
+    protected String getOperationName() {
+        return LOCK;
+    }
+}
diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/UnLock.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/operations/UnLock.java
new file mode 100644 (file)
index 0000000..07b10aa
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.confignetconfconnector.operations;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * Simple unlock implementation that pretends to unlock candidate datastore.
+ * Candidate datastore is allocated per session and is private so no real locking is needed (JMX is the only possible interference)
+ */
+public class UnLock extends AbstractLastNetconfOperation {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UnLock.class);
+
+    private static final String UNLOCK = "unlock";
+
+    public UnLock(final String netconfSessionIdForReporting) {
+        super(netconfSessionIdForReporting);
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+        final Datastore targetDatastore = Lock.extractTargetParameter(operationElement);
+        if(targetDatastore == Datastore.candidate) {
+            // Since candidate datastore instances are allocated per session and not accessible anywhere else, no need to lock
+            LOG.debug("Unlocking {} datastore on session: {}", targetDatastore, getNetconfSessionIdForReporting());
+            // TODO this should fail if we are not locked
+            return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+        }
+
+        // Not supported running lock
+        throw new NetconfDocumentedException("Unable to unlock " + Datastore.running + " datastore", NetconfDocumentedException.ErrorType.application,
+                NetconfDocumentedException.ErrorTag.operation_not_supported, NetconfDocumentedException.ErrorSeverity.error);
+    }
+
+    @Override
+    protected String getOperationName() {
+        return UNLOCK;
+    }
+}
index 294e0c80135a96ab16b9612e3dd502756b290b3f..04d5d4bb6f86a090508e80de08b78b33049b207d 100644 (file)
@@ -14,6 +14,8 @@ import java.util.Set;
 import org.opendaylight.controller.config.util.ConfigRegistryClient;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.Lock;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.UnLock;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Validate;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
@@ -48,6 +50,8 @@ final class NetconfOperationProvider {
         ops.add(new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
                 netconfSessionIdForReporting));
         ops.add(new Commit(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
+        ops.add(new Lock(netconfSessionIdForReporting));
+        ops.add(new UnLock(netconfSessionIdForReporting));
         ops.add(new Get(yangStoreSnapshot, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new DiscardChanges(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
         ops.add(new Validate(transactionProvider, configRegistryClient, netconfSessionIdForReporting));
index beb3365f1c068487ddfb5cbb70883cb81ff14776..6f9a62af1a4857f6c17d6d62c880248c49da42d0 100644 (file)
@@ -83,6 +83,8 @@ import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.Lock;
+import org.opendaylight.controller.netconf.confignetconfconnector.operations.UnLock;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.editconfig.EditConfig;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
 import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
@@ -96,6 +98,7 @@ import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnap
 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
 import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
@@ -236,6 +239,12 @@ public class NetconfMappingTest extends AbstractConfigTest {
 
     }
 
+    @Test
+    public void testUnLock() throws Exception {
+        assertTrue(NetconfMessageUtil.isOKMessage(lockCandidate()));
+        assertTrue(NetconfMessageUtil.isOKMessage(unlockCandidate()));
+    }
+
     private void assertCorrectRefNamesForDependencies(Document config) throws NodeTestException {
         NodeList modulesList = config.getElementsByTagName("modules");
         assertEquals(1, modulesList.getLength());
@@ -383,6 +392,16 @@ public class NetconfMappingTest extends AbstractConfigTest {
         executeOp(commitOp, "netconfMessages/commit.xml");
     }
 
+    private Document lockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
+        Lock commitOp = new Lock(NETCONF_SESSION_ID);
+        return executeOp(commitOp, "netconfMessages/lock.xml");
+    }
+
+    private Document unlockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
+        UnLock commitOp = new UnLock(NETCONF_SESSION_ID);
+        return executeOp(commitOp, "netconfMessages/unlock.xml");
+    }
+
     private Document getConfigCandidate() throws ParserConfigurationException, SAXException, IOException,
             NetconfDocumentedException {
         GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/lock.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/lock.xml
new file mode 100644 (file)
index 0000000..f5228b2
--- /dev/null
@@ -0,0 +1,16 @@
+<!--
+  ~ Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<rpc message-id="101"
+     xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <lock>
+        <target>
+            <candidate/>
+        </target>
+    </lock>
+</rpc>
\ No newline at end of file
diff --git a/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unlock.xml b/opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/unlock.xml
new file mode 100644 (file)
index 0000000..e6e3770
--- /dev/null
@@ -0,0 +1,16 @@
+<!--
+  ~ Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<rpc message-id="101"
+     xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <unlock>
+        <target>
+            <candidate/>
+        </target>
+    </unlock>
+</rpc>
\ No newline at end of file