VERSION | 2
python/example.py | 23 ++++
python/sanlock.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 299 insertions(+), 22 deletions(-)
New commits:
commit 8163bc7b56be4cbe747dc1f3ad9a6f3bca368eb5
Author: David Teigland <teigland(a)redhat.com>
Date: Fri Jul 12 14:10:28 2013 -0500
release 2.8
Signed-off-by: David Teigland <teigland(a)redhat.com>
diff --git a/VERSION b/VERSION
index 1effb00..a4412fa 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.7
+2.8
commit b7ace62d08a71e8eb72e597ec6134f21dfbfee80
Author: Federico Simoncelli <fsimonce(a)redhat.com>
Date: Fri Jun 14 12:15:40 2013 -0400
python: add support to read resource owners
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
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,
commit b1158a23d0d82797472fc1404a90348e60b0cdb4
Author: Federico Simoncelli <fsimonce(a)redhat.com>
Date: Fri Jun 14 12:15:39 2013 -0400
python: add the get_hosts support
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
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
}
commit 69289407971b5c8625a0bc0414c18691c92d9237
Author: Federico Simoncelli <fsimonce(a)redhat.com>
Date: Fri Jun 14 12:15:38 2013 -0400
python: add the support for the resource request
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
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
}
commit 6042d5904fa884ee62dc5e84d2e19814a5509810
Author: Federico Simoncelli <fsimonce(a)redhat.com>
Date: Fri Jun 14 12:15:37 2013 -0400
python: improve example with signals and exceptions
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
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)
commit f1c42c9caacd95ab62988ab6ecb3a6e5422b85eb
Author: Federico Simoncelli <fsimonce(a)redhat.com>
Date: Fri Jun 14 12:15:36 2013 -0400
python: rename SANLK_LSF flags and constants macro
Signed-off-by: Federico Simoncelli <fsimonce(a)redhat.com>
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
}