]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib/smbconf: add python wrapper functions for transaction management
authorJohn Mulligan <jmulligan@redhat.com>
Mon, 25 Apr 2022 16:04:20 +0000 (12:04 -0400)
committerJeremy Allison <jra@samba.org>
Fri, 6 May 2022 18:14:30 +0000 (18:14 +0000)
The smbconf API supports transactions. This changes adds wrapper
functions transaction_start, transaction_commit, and transaction_cancel.
It also adds tests for the functions, one of which demonstrates a
semi-pythonic way to use said functions.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Fri May  6 18:14:30 UTC 2022 on sn-devel-184

lib/smbconf/pysmbconf.c
python/samba/tests/smbconf.py

index 6edca974ccdcf144688b4ecc6a518947eefc55b6..b0aca4508af16466d53f20de6aeab830d85071bc 100644 (file)
@@ -518,6 +518,39 @@ static PyObject *obj_delete_global_parameter(py_SMBConf_Object * self,
        Py_RETURN_NONE;
 }
 
+static PyObject *obj_transaction_start(py_SMBConf_Object * self,
+                                      PyObject * Py_UNUSED(ignored))
+{
+       sbcErr err = smbconf_transaction_start(self->conf_ctx);
+       if (err != SBC_ERR_OK) {
+               py_raise_SMBConfError(err);
+               return NULL;
+       }
+       Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_commit(py_SMBConf_Object * self,
+                                       PyObject * Py_UNUSED(ignored))
+{
+       sbcErr err = smbconf_transaction_commit(self->conf_ctx);
+       if (err != SBC_ERR_OK) {
+               py_raise_SMBConfError(err);
+               return NULL;
+       }
+       Py_RETURN_NONE;
+}
+
+static PyObject *obj_transaction_cancel(py_SMBConf_Object * self,
+                                       PyObject * Py_UNUSED(ignored))
+{
+       sbcErr err = smbconf_transaction_cancel(self->conf_ctx);
+       if (err != SBC_ERR_OK) {
+               py_raise_SMBConfError(err);
+               return NULL;
+       }
+       Py_RETURN_NONE;
+}
+
 PyDoc_STRVAR(obj_requires_messaging_doc,
 "requires_messaging() -> bool\n"
 "\n"
@@ -583,6 +616,19 @@ PyDoc_STRVAR(obj_delete_global_parameter_doc,
 "delete_parameter(str, str) -> None\n"
 "Delete a single global configuration parameter.\n");
 
+PyDoc_STRVAR(obj_transaction_start_doc,
+"transaction_start() -> None\n"
+"Start a transaction.\n"
+"Transactions allow making compound sets of changes atomically.\n");
+
+PyDoc_STRVAR(obj_transaction_commit_doc,
+"transaction_commit() -> None\n"
+"Commit the transaction.\n");
+
+PyDoc_STRVAR(obj_transaction_cancel_doc,
+"transaction_cancel() -> None\n"
+"Cancel the transaction.\n");
+
 static PyMethodDef py_smbconf_obj_methods[] = {
        { "requires_messaging", (PyCFunction) obj_requires_messaging,
         METH_NOARGS, obj_requires_messaging_doc },
@@ -610,6 +656,12 @@ static PyMethodDef py_smbconf_obj_methods[] = {
         obj_delete_parameter_doc },
        { "delete_global_parameter", (PyCFunction) obj_delete_global_parameter,
         METH_VARARGS, obj_delete_global_parameter_doc },
+       { "transaction_start", (PyCFunction) obj_transaction_start, METH_NOARGS,
+        obj_transaction_start_doc },
+       { "transaction_commit", (PyCFunction) obj_transaction_commit,
+        METH_NOARGS, obj_transaction_commit_doc },
+       { "transaction_cancel", (PyCFunction) obj_transaction_cancel,
+        METH_NOARGS, obj_transaction_cancel_doc },
        { 0 },
 };
 
index cebad7fba11228eb2c3574c8bb72c0847e8d2555..e023e2ad59b148ff9518996db33473bb8871f987 100644 (file)
@@ -259,6 +259,71 @@ class SMBConfTests(samba.tests.TestCase):
         s1 = sconf.get_share("global")
         self.assertEqual(s1, ("global", [("workgroup", "EXAMPLE")]))
 
+    def test_transaction_direct(self):
+        sconf = self.s3smbconf.init_reg(None)
+        sconf.drop()
+        sconf.set_global_parameter("workgroup", "EXAMPLE")
+
+        sconf.transaction_start()
+        sconf.set_global_parameter("client min protocol", "NT1")
+        sconf.set_global_parameter("server min protocol", "SMB2")
+        sconf.transaction_cancel()
+
+        s1 = sconf.get_share("global")
+        self.assertEqual(s1, ("global", [("workgroup", "EXAMPLE")]))
+
+        sconf.transaction_start()
+        sconf.set_global_parameter("client min protocol", "NT1")
+        sconf.set_global_parameter("server min protocol", "SMB2")
+        sconf.transaction_commit()
+
+        s1 = sconf.get_share("global")
+        self.assertEqual(
+            s1,
+            (
+                "global",
+                [
+                    ("workgroup", "EXAMPLE"),
+                    ("client min protocol", "NT1"),
+                    ("server min protocol", "SMB2"),
+                ],
+            ),
+        )
+
+    def test_transaction_tryexc(self):
+        sconf = self.s3smbconf.init_reg(None)
+        sconf.drop()
+
+        def _mkshares(shares):
+            sconf.transaction_start()
+            try:
+                for name, params in shares:
+                    sconf.create_set_share(name, params)
+                sconf.transaction_commit()
+            except Exception:
+                sconf.transaction_cancel()
+                raise
+
+        _mkshares(
+            [
+                ("hello", [("path", "/srv/world")]),
+                ("goodnight", [("path", "/srv/moon")]),
+            ]
+        )
+        # this call to _mkshares will fail the whole transaction because
+        # share name "goodnight" already exists
+        self.assertRaises(
+            self.smbconf.SMBConfError,
+            _mkshares,
+            [
+                ("mars", [("path", "/srv/mars")]),
+                ("goodnight", [("path", "/srv/phobos")]),
+            ],
+        )
+
+        names = sconf.share_names()
+        self.assertEqual(names, ["hello", "goodnight"])
+
 
 if __name__ == "__main__":
     import unittest