{ "info": { "author": "Justin Giorgi", "author_email": "justin@justingiorgi.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", "Programming Language :: Python :: 2", "Programming Language :: Python :: 3", "Topic :: Utilities" ], "description": "Hierarchical Resource Locking System\r\n====================================\r\n\r\nLocker exists to allow the coordination of resource locks across independent or distributed systems.\r\nSystems utilizing Locker could be simple scripts, CI jobs or even separate network nodes, they only\r\nneed to be able to query the Locker instance via HTTP.\r\n\r\nLocker is different from a standard sephemore system in that it understands resources as a\r\nhierarchy. Resources are nested in the url path ie: \"/foo/bar\" where \"bar\" is a child of \"foo\".\r\nIf a lock exists on \"/foo/bar\" the parent (\"/foo\") cannot be locked because one of its children is\r\nlocked. Likewise a child of \"/foo/bar\" such as \"/foo/bar/baz\" cannot be locked because its parent\r\nis locked. A sibling such as \"/foo/zip\" could be locked.\r\n\r\nResource names are completely arbitrary and not mapped to any physical resources. The systems\r\nquerying Locker are trusted not to utilize locked resources and to free resources when they are no\r\nlonger needed.\r\n\r\n\r\nInitialization\r\n--------------\r\n\r\nLocker can be initialized by running the __init__.py in the Locker directory directly. This will\r\ninitialize Locker with an HTTP server on the default IP and port (127.0.0.1:8765). With locks being\r\nserialized to \"locks.db\". These options can be modified using command line arguments.\r\n\r\n.. code-block:: bash\r\n\t$ locker/__init__.py --ip 0.0.0.0 --port 8080 --file mylocks.dat\r\n\t\r\nLocker can also be used as a component of a larger system. Import the Locker object and initialize\r\nwith runserver=False. If your system uses CherryPy the api methods of Locker are already decorated\r\nwith @expose. Note that even running without its web server Locker API methods return jsonified\r\ndata. See help(Locker) for more details.\r\n\r\n.. code-block:: python\r\n\tfrom locker import Locker\r\n\t\r\n\tlocker = Locker(runserver=False)\r\n\t\r\n\r\nBasic Usage\r\n-----------\r\n\r\nLocker exposes three API methods to lock, unlock and query for resources. Respectively these are \r\n\"canhaz\", \"nowant\" and \"dohaz\". The requests module is recommended when using Python to call the\r\nLocker API but anything capable of HTTP calls will work.\r\n\r\nLocking Resources\r\n#################\r\n\r\nLocking or reserving resources is done with the canhaz call. This call checks if the resource is\r\nlocked and if unlocked returns OK and a token to use when unlocking the resource. WARNING: the\r\nresource cannot be unlocked without this token.\r\n\r\nThe example below locks the resource \"/my/resource\".\r\n\r\n.. code-block:: python\r\n\t>>> response = get(\"http://localhost:8765/canhaz/my/resource\")\r\n\t>>> response.json()\r\n\t{u'token': u'cb7edb5c-6b7c-4b60-b127-3a7e344f00d0', u'ok': True}\r\n\t\r\nIf another attempt is made to lock the same resource (or a parent or child of /my/resource) the\r\nrequest will fail.\r\n\r\n.. code-block:: python\r\n\t>>> response = get(\"http://localhost:8765/canhaz/my/resource\")\r\n\t>>> response.json()\r\n\t{u'ok': False, u'lockedBy': u'?'}\r\n\t\r\nMore on the lockedBy field in the Advanced Usage section.\r\n\r\n\r\nUnlocking Resources\r\n###################\r\n\r\nUnlocking resources is done with the nowant call. This call succeeds if the resource is locked and\r\nthe token is valid to unlock it.\r\n\r\n.. code-block:: python\r\n\t>>> response = get(\"http://localhost:8765/nowant/my/resource?token=cb7edb5c-6b7c-4b60-b127-3a7e344f00d0\")\r\n\t>>> response.json()\r\n\t{u'ok': True}\r\n\t\r\nIf the resource is not locked or the token is invalid the call will fail.\r\n\r\n.. code-block:: python\r\n\t>>> response = get(\"http://localhost:8765/nowant/my/resource?token=invalid-token\")\r\n\t>>> response.json()\r\n\t{u'ok': False}\r\n\r\n\t\r\nQuerying the State of Resources\r\n###############################\r\n\r\nThe state of any resource can be retrieved by a dohaz call. This call provides the id of the caller\r\nthat locked the resource (if available), \"?\" if the id of the caller is not known or None if the\r\nresource is not locked.\r\n\r\nThe example below show a locked resource.\r\n\r\n.. code-block:: python\r\n\t>>> response = get(\"http://localhost:8765/dohaz/my/resource\")\r\n\t>>> response.json()\r\n\t{u'lockedBy': u'?'}\r\n\t\r\nThis example shows an unlocked resource.\r\n\r\n.. code-block:: python\r\n\t>>> response = get(\"http://localhost:8765/dohaz/some/resource\")\r\n\t>>> response.json()\r\n\t{u'lockedBy': None}\r\n\t\r\n\t\r\nAdvanced Usage\r\n--------------\r\n\r\nIn addition to the standard functionality documented above Locker supports identification of the\r\ncaller that owns a resource lock as well as modifications of the locking behavior.\r\n\r\nCaller Identification\r\n#####################\r\n\r\nIn several of the basic examples the lockedBy field was returned showing only \"?\". To properly\r\nidentify the owner of a resource lock the caller can provide an id when locking the resource. The\r\nid will then be returned in future queries to canhaz and dohaz as the lockedBy field.\r\n\r\n.. code-block:: python\r\n\t>>> response = get(\"http://localhost:8765/canhaz/this?id=timmy\")\r\n\t>>> response.json()\r\n\t{u'token': u'15b536b9-97b3-430b-8c5f-14261c97f782', u'ok': True}\r\n\t\r\n\t>>> response = get(\"http://localhost:8765/dohaz/this\")\r\n\t>>> response.json()\r\n\t{u'lockedBy': u'timmy'}\r\n\t\r\nIDs are arbitrary strings and are optional when locking a resource.\r\n\r\n\r\nLocking Behavior Modifications\r\n##############################\r\n\r\nAthough not common you may have a need to lock a resource without locking its parents or without\r\nlocking its children. This is supported when locking the resource by passing additional arguments to\r\nthe canhaz call.\r\n\r\nThis is an example of locking a resource without locking its parent(s):\r\n\r\n.. code-block:: python\r\n\t>>> get(\"http://localhost:8765/canhaz/foo/bar?lockParents=False\")\r\n\t\r\n\t>>> response = get(\"http://localhost:8765/canhaz/foo\")\r\n\t>>> response.json()\r\n\t{u'token': u'd305eb3a-2fec-4db1-9448-47cec24c169f', u'ok': True}\r\n\t\r\nAnd this is an example of locking a resource without locking its child(ren):\r\n\r\n.. code-block:: python\r\n\t>>> get(\"http://localhost:8765/canhaz/bar?lockChildren=False\")\r\n\t\r\n\t>>> response = get(\"http://localhost:8765/canhaz/bar/foo\")\r\n\t>>> response.json()\r\n\t{u'token': u'72ad7aaa-3529-4f84-ae6b-23200fcbb731', u'ok': True}\r\n\t\r\nThese flags can be used together if desired.\r\n\r\n", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://bitbucket.org/jgiorgi/locker", "keywords": "resource lock sephemore hierarchy nested", "license": "GPLv3", "maintainer": null, "maintainer_email": null, "name": "Locker", "package_url": "https://pypi.org/project/Locker/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/Locker/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://bitbucket.org/jgiorgi/locker" }, "release_url": "https://pypi.org/project/Locker/1.0b/", "requires_dist": null, "requires_python": null, "summary": "Hierarchical Resource Locking Mechanism", "version": "1.0b" }, "last_serial": 1488351, "releases": { "1.0b": [ { "comment_text": "", "digests": { "md5": "d9a73c404124c59eb623b1172a0a2ec6", "sha256": "e6be49dfbeb5b3c97ec6fd9b727051fe62889c532d2af103fafb86f333091440" }, "downloads": -1, "filename": "Locker-1.0b.zip", "has_sig": false, "md5_digest": "d9a73c404124c59eb623b1172a0a2ec6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6280, "upload_time": "2015-04-02T15:59:25", "url": "https://files.pythonhosted.org/packages/86/65/c9f142235940e06ad3d335244a222cd828f03e1c84581a0f2c966fe000cd/Locker-1.0b.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "d9a73c404124c59eb623b1172a0a2ec6", "sha256": "e6be49dfbeb5b3c97ec6fd9b727051fe62889c532d2af103fafb86f333091440" }, "downloads": -1, "filename": "Locker-1.0b.zip", "has_sig": false, "md5_digest": "d9a73c404124c59eb623b1172a0a2ec6", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 6280, "upload_time": "2015-04-02T15:59:25", "url": "https://files.pythonhosted.org/packages/86/65/c9f142235940e06ad3d335244a222cd828f03e1c84581a0f2c966fe000cd/Locker-1.0b.zip" } ] }