Signed-off-by: Federico Simoncelli fsimonce@redhat.com --- python/sanlock.c | 24 ++++++++++++------------ 1 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/python/sanlock.c b/python/sanlock.c index 7d39deb..13919ea 100644 --- a/python/sanlock.c +++ b/python/sanlock.c @@ -697,9 +697,9 @@ PyDoc_STRVAR(pydoc_get_lockspaces, "\ get_lockspaces() -> dict\n\ Return the list of lockspaces currently managed by sanlock. The reported\n\ flag indicates whether the lockspace is acquired (0) or in transition.\n\ -The possible transition values are SANLK_LSF_ADD if the lockspace is in\n\ -the process of being acquired, and SANLK_LSF_REM if it's in the process\n\ -of being released.\n"); +The possible transition values are LSFLAG_ADD if the lockspace is in the\n\ +process of being acquired, and LSFLAG_REM if it's in the process of being\n\ +released.\n");
static PyObject * py_get_lockspaces(PyObject *self __unused, PyObject *args, PyObject *keywds) @@ -1095,15 +1095,15 @@ initsanlock(void) Py_INCREF(py_exception); }
- if ((sk_constant = PyInt_FromLong(SANLK_LSF_ADD)) != NULL) { - if (PyModule_AddObject(py_module, "SANLK_LSF_ADD", sk_constant)) { - Py_DECREF(sk_constant); - } +#define PYSNLK_INIT_ADD_CONSTANT(x, y) \ + if ((sk_constant = PyInt_FromLong(x)) != NULL) { \ + if (PyModule_AddObject(py_module, y, sk_constant)) { \ + Py_DECREF(sk_constant); \ + } \ }
- if ((sk_constant = PyInt_FromLong(SANLK_LSF_REM)) != NULL) { - if (PyModule_AddObject(py_module, "SANLK_LSF_REM", sk_constant)) { - Py_DECREF(sk_constant); - } - } + PYSNLK_INIT_ADD_CONSTANT(SANLK_LSF_ADD, "LSFLAG_ADD"); + PYSNLK_INIT_ADD_CONSTANT(SANLK_LSF_REM, "LSFLAG_REM"); + +#undef PYSNLK_INIT_ADD_CONSTANT }
Signed-off-by: Federico Simoncelli fsimonce@redhat.com --- python/example.py | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/python/example.py b/python/example.py index 354579e..875ddc8 100644 --- a/python/example.py +++ b/python/example.py @@ -1,4 +1,5 @@ import os +import signal import tempfile import sanlock
@@ -6,7 +7,12 @@ HOST_ID = 1 LOCKSPACE_NAME = "lockspace1" RESOURCE_NAME = "resource1"
+def sigTermHandler(): + print "SIGTERM signal received" + def main(): + signal.signal(signal.SIGTERM, sigTermHandler) + print "Creating the sanlock disk" fd, disk = tempfile.mkstemp() os.close(fd) @@ -33,6 +39,8 @@ def main(): version=0) print "Releasing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.release(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd) + except Exception as e: + print "Exception: ", e finally: print "Releasing the id '%i' on '%s'" % (HOST_ID, LOCKSPACE_NAME) sanlock.rem_lockspace(LOCKSPACE_NAME, HOST_ID, disk)
Signed-off-by: Federico Simoncelli fsimonce@redhat.com --- python/sanlock.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 84 insertions(+), 7 deletions(-)
diff --git a/python/sanlock.c b/python/sanlock.c index 13919ea..6ad3469 100644 --- a/python/sanlock.c +++ b/python/sanlock.c @@ -462,7 +462,7 @@ py_read_resource(PyObject *self __unused, PyObject *args, PyObject *keywds) goto exit_fail;
/* fill the dictionary information: version */ - if ((rs_entry = PyInt_FromLong(rs->lver)) == NULL) + if ((rs_entry = PyLong_FromUnsignedLong(rs->lver)) == NULL) goto exit_fail; rv = PyDict_SetItemString(rs_info, "version", rs_entry); Py_DECREF(rs_entry); @@ -788,7 +788,7 @@ exit_fail: /* acquire */ PyDoc_STRVAR(pydoc_acquire, "\ acquire(lockspace, resource, disks \ -[, slkfd=fd, pid=owner, shared=False, version=0])\n\ +[, slkfd=fd, pid=owner, shared=False, version=None])\n\ Acquire a resource lease for the current process (using the slkfd argument\n\ to specify the sanlock file descriptor) or for an other process (using the\n\ pid argument). If shared is True the resource will be acquired in the shared\n\ @@ -798,16 +798,16 @@ The disks must be in the format: [(path, offset), ... ]\n"); static PyObject * py_acquire(PyObject *self __unused, PyObject *args, PyObject *keywds) { - int rv, sanlockfd = -1, pid = -1, shared = 0, version = 0; + int rv, sanlockfd = -1, pid = -1, shared = 0; const char *lockspace, *resource; struct sanlk_resource *res; - PyObject *disks; + PyObject *disks, *version = Py_None;
static char *kwlist[] = {"lockspace", "resource", "disks", "slkfd", "pid", "shared", "version", NULL};
/* parse python tuple */ - if (!PyArg_ParseTupleAndKeywords(args, keywds, "ssO!|iiii", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ssO!|iiiO", kwlist, &lockspace, &resource, &PyList_Type, &disks, &sanlockfd, &pid, &shared, &version)) { return NULL; @@ -834,9 +834,13 @@ py_acquire(PyObject *self __unused, PyObject *args, PyObject *keywds) }
/* prepare the resource version */ - if (version) { + if (version != Py_None) { res->flags |= SANLK_RES_LVER; - res->lver = version; + res->lver = PyInt_AsUnsignedLongMask(version); + if (res->lver == -1) { + __set_exception(EINVAL, "Unable to convert the version value"); + goto exit_fail; + } }
/* acquire sanlock resource (gil disabled) */ @@ -907,6 +911,72 @@ exit_fail: return NULL; }
+/* request */ +PyDoc_STRVAR(pydoc_request, "\ +request(lockspace, resource, disks [, action=REQ_GRACEFUL, version=None])\n\ +Request the owner of a resource to do something specified by action.\n\ +The possible values for action are: REQ_GRACEFUL to request a graceful\n\ +release of the resource and REQ_FORCE to sigkill the owner of the\n\ +resource (forcible release). The version should be either the next version\n\ +to acquire or None (which automatically uses the next version).\n\ +The disks must be in the format: [(path, offset), ... ]"); + +static PyObject * +py_request(PyObject *self __unused, PyObject *args, PyObject *keywds) +{ + int rv, action = SANLK_REQ_GRACEFUL, flags = 0; + const char *lockspace, *resource; + struct sanlk_resource *res; + PyObject *disks, *version = Py_None; + + static char *kwlist[] = {"lockspace", "resource", "disks", "action", + "version", NULL}; + + /* parse python tuple */ + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ssO!|iO", kwlist, + &lockspace, &resource, &PyList_Type, &disks, &action, &version)) { + return NULL; + } + + /* parse and check sanlock resource */ + if (__parse_resource(disks, &res) < 0) { + return NULL; + } + + /* prepare sanlock names */ + strncpy(res->lockspace_name, lockspace, SANLK_NAME_LEN); + strncpy(res->name, resource, SANLK_NAME_LEN); + + /* prepare the resource version */ + if (version == Py_None) { + flags = SANLK_REQUEST_NEXT_LVER; + } else { + res->flags |= SANLK_RES_LVER; + res->lver = PyInt_AsUnsignedLongMask(version); + if (res->lver == -1) { + __set_exception(EINVAL, "Unable to convert the version value"); + goto exit_fail; + } + } + + /* request sanlock resource (gil disabled) */ + Py_BEGIN_ALLOW_THREADS + rv = sanlock_request(flags, action, res); + Py_END_ALLOW_THREADS + + if (rv != 0) { + __set_exception(rv, "Sanlock request not submitted"); + goto exit_fail; + } + + free(res); + Py_RETURN_NONE; + +exit_fail: + free(res); + return NULL; +} + /* killpath */ PyDoc_STRVAR(pydoc_killpath, "\ killpath(path, args [, slkfd=fd])\n\ @@ -1035,6 +1105,8 @@ sanlock_methods[] = { METH_VARARGS|METH_KEYWORDS, pydoc_acquire}, {"release", (PyCFunction) py_release, METH_VARARGS|METH_KEYWORDS, pydoc_release}, + {"request", (PyCFunction) py_request, + METH_VARARGS|METH_KEYWORDS, pydoc_request}, {"killpath", (PyCFunction) py_killpath, METH_VARARGS|METH_KEYWORDS, pydoc_killpath}, {NULL, NULL, 0, NULL} @@ -1102,8 +1174,13 @@ initsanlock(void) } \ }
+ /* lockspaces list flags */ PYSNLK_INIT_ADD_CONSTANT(SANLK_LSF_ADD, "LSFLAG_ADD"); PYSNLK_INIT_ADD_CONSTANT(SANLK_LSF_REM, "LSFLAG_REM");
+ /* resource request flags */ + PYSNLK_INIT_ADD_CONSTANT(SANLK_REQ_FORCE, "REQ_FORCE"); + PYSNLK_INIT_ADD_CONSTANT(SANLK_REQ_GRACEFUL, "REQ_GRACEFUL"); + #undef PYSNLK_INIT_ADD_CONSTANT }
Signed-off-by: Federico Simoncelli fsimonce@redhat.com --- python/example.py | 12 +++++ python/sanlock.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 137 insertions(+), 2 deletions(-)
diff --git a/python/example.py b/python/example.py index 875ddc8..f3cd414 100644 --- a/python/example.py +++ b/python/example.py @@ -1,4 +1,5 @@ import os +import time import signal import tempfile import sanlock @@ -37,6 +38,17 @@ def main(): print "Acquiring '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.acquire(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd, version=0) + while True: + print "Trying to get lockspace '%s' hosts" % LOCKSPACE_NAME + try: + hosts_list = sanlock.get_hosts(LOCKSPACE_NAME) + except sanlock.SanlockException as e: + if e.errno != os.errno.EAGAIN: + raise + else: + print "Lockspace '%s' hosts: " % LOCKSPACE_NAME, hosts_list + break + time.sleep(5) print "Releasing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.release(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd) except Exception as e: diff --git a/python/sanlock.c b/python/sanlock.c index 6ad3469..c1067ae 100644 --- a/python/sanlock.c +++ b/python/sanlock.c @@ -134,6 +134,75 @@ exit_fail: return -1; }
+static PyObject * +__hosts_to_list(struct sanlk_host *hss, int hss_count) +{ + int i, rv; + PyObject *ls_list = NULL, *ls_entry = NULL, *ls_value = NULL; + + /* prepare the dictionary holding the information */ + if ((ls_list = PyList_New(0)) == NULL) + goto exit_fail; + + for (i = 0; i < hss_count; i++) { + if ((ls_entry = PyDict_New()) == NULL) + goto exit_fail; + + /* fill the dictionary information: host_id */ + if ((ls_value = PyInt_FromLong(hss[i].host_id)) == NULL) + goto exit_fail; + rv = PyDict_SetItemString(ls_entry, "host_id", ls_value); + Py_DECREF(ls_value); + if (rv != 0) + goto exit_fail; + + /* fill the dictionary information: generation */ + if ((ls_value = PyInt_FromLong(hss[i].generation)) == NULL) + goto exit_fail; + rv = PyDict_SetItemString(ls_entry, "generation", ls_value); + Py_DECREF(ls_value); + if (rv != 0) + goto exit_fail; + + /* fill the dictionary information: timestamp */ + if ((ls_value = PyInt_FromLong(hss[i].timestamp)) == NULL) + goto exit_fail; + rv = PyDict_SetItemString(ls_entry, "timestamp", ls_value); + Py_DECREF(ls_value); + if (rv != 0) + goto exit_fail; + + /* fill the dictionary information: io_timeout */ + if ((ls_value = PyInt_FromLong(hss[i].io_timeout)) == NULL) + goto exit_fail; + rv = PyDict_SetItemString(ls_entry, "io_timeout", ls_value); + Py_DECREF(ls_value); + if (rv != 0) + goto exit_fail; + + /* fill the dictionary information: flags */ + if ((ls_value = PyInt_FromLong(hss[i].flags)) == NULL) + goto exit_fail; + rv = PyDict_SetItemString(ls_entry, "flags", ls_value); + Py_DECREF(ls_value); + if (rv != 0) + goto exit_fail; + + if (PyList_Append(ls_list, ls_entry) != 0) + goto exit_fail; + + Py_DECREF(ls_entry); + } + + return ls_list; + + /* failure */ +exit_fail: + Py_XDECREF(ls_entry); + Py_XDECREF(ls_list); + return NULL; +} + /* register */ PyDoc_STRVAR(pydoc_register, "\ register() -> int\n\ @@ -694,7 +763,7 @@ py_rem_lockspace(PyObject *self __unused, PyObject *args, PyObject *keywds)
/* get_lockspaces */ PyDoc_STRVAR(pydoc_get_lockspaces, "\ -get_lockspaces() -> dict\n\ +get_lockspaces() -> list\n\ Return the list of lockspaces currently managed by sanlock. The reported\n\ flag indicates whether the lockspace is acquired (0) or in transition.\n\ The possible transition values are LSFLAG_ADD if the lockspace is in the\n\ @@ -714,7 +783,7 @@ py_get_lockspaces(PyObject *self __unused, PyObject *args, PyObject *keywds) Py_END_ALLOW_THREADS
if (rv < 0) { - __set_exception(rv, "Sanlock get lockspace failure"); + __set_exception(rv, "Sanlock get lockspaces failure"); goto exit_fail; }
@@ -784,6 +853,51 @@ exit_fail: return NULL; }
+/* get_hosts */ +PyDoc_STRVAR(pydoc_get_hosts, "\ +get_hosts(lockspace, host_id=0) -> list\n\ +Return the list of hosts currently alive in a lockspace. When the host_id\n\ +is specified then only the requested host status is returned. The reported\n\ +flag indicates whether the host is free (HOST_FREE), alive (HOST_LIVE),\n\ +failing (HOST_FAIL), dead (HOST_DEAD) or unknown (HOST_UNKNOWN).\n\ +The unknown state is the default when sanlock just joined the lockspace\n\ +and didn't collect enough information to determine the real status of other\n\ +hosts. The dictionary returned also contains: the generation, the last\n\ +timestamp and the io_timeout.\n"); + +static PyObject * +py_get_hosts(PyObject *self __unused, PyObject *args, PyObject *keywds) +{ + int rv, hss_count = 0; + uint64_t host_id = 0; + const char *lockspace = NULL; + struct sanlk_host *hss = NULL; + PyObject *ls_list = NULL; + + static char *kwlist[] = {"lockspace", "host_id", NULL}; + + /* parse python tuple */ + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|k", kwlist, + &lockspace, &host_id)) { + return NULL; + } + + /* get all the lockspaces (gil disabled) */ + Py_BEGIN_ALLOW_THREADS + rv = sanlock_get_hosts(lockspace, host_id, &hss, &hss_count, 0); + Py_END_ALLOW_THREADS + + if (rv < 0) { + __set_exception(rv, "Sanlock get hosts failure"); + goto exit_fail; + } + + ls_list = __hosts_to_list(hss, hss_count); + +exit_fail: + if (hss) free(hss); + return ls_list; +}
/* acquire */ PyDoc_STRVAR(pydoc_acquire, "\ @@ -1101,6 +1215,8 @@ sanlock_methods[] = { METH_VARARGS|METH_KEYWORDS, pydoc_rem_lockspace}, {"get_lockspaces", (PyCFunction) py_get_lockspaces, METH_VARARGS|METH_KEYWORDS, pydoc_get_lockspaces}, + {"get_hosts", (PyCFunction) py_get_hosts, + METH_VARARGS|METH_KEYWORDS, pydoc_get_hosts}, {"acquire", (PyCFunction) py_acquire, METH_VARARGS|METH_KEYWORDS, pydoc_acquire}, {"release", (PyCFunction) py_release, @@ -1182,5 +1298,12 @@ initsanlock(void) PYSNLK_INIT_ADD_CONSTANT(SANLK_REQ_FORCE, "REQ_FORCE"); PYSNLK_INIT_ADD_CONSTANT(SANLK_REQ_GRACEFUL, "REQ_GRACEFUL");
+ /* hosts list flags */ + PYSNLK_INIT_ADD_CONSTANT(SANLK_HOST_FREE, "HOST_FREE"); + PYSNLK_INIT_ADD_CONSTANT(SANLK_HOST_LIVE, "HOST_LIVE"); + PYSNLK_INIT_ADD_CONSTANT(SANLK_HOST_FAIL, "HOST_FAIL"); + PYSNLK_INIT_ADD_CONSTANT(SANLK_HOST_DEAD, "HOST_DEAD"); + PYSNLK_INIT_ADD_CONSTANT(SANLK_HOST_UNKNOWN, "HOST_UNKNOWN"); + #undef PYSNLK_INIT_ADD_CONSTANT }
Signed-off-by: Federico Simoncelli fsimonce@redhat.com --- python/example.py | 3 ++ python/sanlock.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/python/example.py b/python/example.py index f3cd414..14e81a8 100644 --- a/python/example.py +++ b/python/example.py @@ -49,6 +49,9 @@ def main(): print "Lockspace '%s' hosts: " % LOCKSPACE_NAME, hosts_list break time.sleep(5) + print "Resource '%s' owners: " % RESOURCE_NAME, \ + sanlock.read_resource_owners( + LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS) print "Releasing '%s' on '%s'" % (RESOURCE_NAME, LOCKSPACE_NAME) sanlock.release(LOCKSPACE_NAME, RESOURCE_NAME, SNLK_DISKS, slkfd=fd) except Exception as e: diff --git a/python/sanlock.c b/python/sanlock.c index c1067ae..b62b8bc 100644 --- a/python/sanlock.c +++ b/python/sanlock.c @@ -1091,6 +1091,58 @@ exit_fail: return NULL; }
+/* read_resource_owners */ +PyDoc_STRVAR(pydoc_read_resource_owners, "\ +read_resource_owners(lockspace, resource, disks) -> list\n\ +Returns the list of hosts owning a resource, the list is not filtered and\n\ +it might contain hosts that are currently failing or dead. The hosts are\n\ +returned in the same format used by get_hosts.\n\ +The disks must be in the format: [(path, offset), ... ]"); + +static PyObject * +py_read_resource_owners(PyObject *self __unused, PyObject *args, PyObject *keywds) +{ + int rv, hss_count = 0; + const char *lockspace, *resource; + struct sanlk_resource *res = NULL; + struct sanlk_host *hss = NULL; + PyObject *disks, *ls_list = NULL; + + static char *kwlist[] = {"lockspace", "resource", "disks", NULL}; + + /* parse python tuple */ + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ssO!", kwlist, + &lockspace, &resource, &PyList_Type, &disks)) { + return NULL; + } + + /* parse and check sanlock resource */ + if (__parse_resource(disks, &res) < 0) { + return NULL; + } + + /* prepare sanlock names */ + strncpy(res->lockspace_name, lockspace, SANLK_NAME_LEN); + strncpy(res->name, resource, SANLK_NAME_LEN); + + /* read resource owners (gil disabled) */ + Py_BEGIN_ALLOW_THREADS + rv = sanlock_read_resource_owners(res, 0, &hss, &hss_count); + Py_END_ALLOW_THREADS + + if (rv != 0) { + __set_exception(rv, "Unable to read resource owners"); + goto exit_fail; + } + + ls_list = __hosts_to_list(hss, hss_count); + +exit_fail: + if (res) free(res); + if (hss) free(hss); + return ls_list; +} + /* killpath */ PyDoc_STRVAR(pydoc_killpath, "\ killpath(path, args [, slkfd=fd])\n\ @@ -1217,6 +1269,8 @@ sanlock_methods[] = { METH_VARARGS|METH_KEYWORDS, pydoc_get_lockspaces}, {"get_hosts", (PyCFunction) py_get_hosts, METH_VARARGS|METH_KEYWORDS, pydoc_get_hosts}, + {"read_resource_owners", (PyCFunction) py_read_resource_owners, + METH_VARARGS|METH_KEYWORDS, pydoc_read_resource_owners}, {"acquire", (PyCFunction) py_acquire, METH_VARARGS|METH_KEYWORDS, pydoc_acquire}, {"release", (PyCFunction) py_release,
sanlock-devel@lists.fedorahosted.org