Giter VIP home page Giter VIP logo

consul-lock's Introduction

Build Status codecov PyPI version

Consul Lock

CLI and Python interface for easily managing Consul locks

About

  • CLI & Python interface:
    • Acquire and release a lock.
    • Execute shell whilst holding a lock (releasing on exit).
    • Set TTL of the session that acquires a lock.
    • Blocking and non-blocking locking.
    • Lock acquire timeouts.
    • Add extra metadata to lock information (useful for monitoring who is holding locks).
    • Specify lock event listeners to be fired before lock acquire is attempted and if unable to acquire locked lock.
  • CLI:
    • Release multiple locks with keys that match regular expression.
    • Meaningful exit codes (see configuration.py for details).
    • JSON output on stdout.
    • Add extra verbosity on stderr with -vv.
  • Python interface:
    • Release multiple locks.
    • Find and release multiple locks with keys that match regular expression.
    • Type hinting.

Installation

Prerequisites:

  • python >= 3.6

The tool can be installed from PyPi:

pip install consullock

Bleeding edge versions can be installed directly from GitHub:

pip install git+https://github.com/wtsi-hgi/consul-lock.git@master#egg=consullock

Usage

CLI

Setup

Set environment variables:

export CONSUL_HTTP_ADDR=consul.example.com:8500
export CONSUL_HTTP_TOKEN=token

General

usage: consul-lock [-h] [-v] {unlock,lock,execute} ...

Tool to use locks in Consul (v4.2.0)

positional arguments:
  {unlock,lock,execute}
                        action
    unlock              release a lock
    lock                acquire a lock
    execute             call executable whilst holding lock

optional arguments:
  -h, --help            show this help message and exit
  -v                    increase the level of log verbosity (add multiple
                        increase further)

Locking

usage: consul-lock lock [-h] [--session-ttl SESSION_TTL] [--non-blocking]
                        [--timeout TIMEOUT] [--metadata METADATA]
                        [--on-before-lock ON_BEFORE_LOCK [ON_BEFORE_LOCK ...]]
                        [--on-already-locked ON_ALREADY_LOCKED [ON_ALREADY_LOCKED ...]]
                        [-i I]
                        key

positional arguments:
  key                   the lock identifier

optional arguments:
  -h, --help            show this help message and exit
  --session-ttl SESSION_TTL
                        time to live (ttl) in seconds of the session that will
                        be created to hold the lock. Must be between 10s and
                        86400s (inclusive). If set to 0, the session will not
                        expire
  --non-blocking        do not block if cannot lock straight away
  --timeout TIMEOUT     give up trying to acquire the key after this many
                        seconds (where 0 is never)
  --metadata METADATA   additional metadata to add to the lock information
                        (will be converted to JSON)
  --on-before-lock ON_BEFORE_LOCK [ON_BEFORE_LOCK ...]
                        path to executable that is to be called before an
                        attempt is made to acquire a lock, where the lock key
                        is passed as the first argument. Any failures of this
                        executable are ignored
  --on-already-locked ON_ALREADY_LOCKED [ON_ALREADY_LOCKED ...]
                        path to executable that is to be called after an
                        attempt has been made to acquire a lock but failed due
                        to the lock already been taken, where the lock key is
                        passed as the first argument. Any failures of this
                        executable are ignored
  -i I                  number of seconds between polls to acquire a locked
                        lock

Unlocking

usage: consul-lock unlock [-h] [-r] key

positional arguments:
  key         the lock identifier

optional arguments:
  -h, --help  show this help message and exit
  -r          whether the key should be treated as a regular expression and to
              release all matching locks

Executing with lock

usage: consul-lock execute [-h] [--session-ttl SESSION_TTL] [--non-blocking]
                           [--timeout TIMEOUT] [--metadata METADATA]
                           [--on-before-lock ON_BEFORE_LOCK [ON_BEFORE_LOCK ...]]
                           [--on-already-locked ON_ALREADY_LOCKED [ON_ALREADY_LOCKED ...]]
                           [-i I]
                           key executable

positional arguments:
  key                   the lock identifier
  executable            to execute in shell

optional arguments:
  -h, --help            show this help message and exit
  --session-ttl SESSION_TTL
                        time to live (ttl) in seconds of the session that will
                        be created to hold the lock. Must be between 10s and
                        86400s (inclusive). If set to 0, the session will not
                        expire
  --non-blocking        do not block if cannot lock straight away
  --timeout TIMEOUT     give up trying to acquire the key after this many
                        seconds (where 0 is never)
  --metadata METADATA   additional metadata to add to the lock information
                        (will be converted to JSON)
  --on-before-lock ON_BEFORE_LOCK [ON_BEFORE_LOCK ...]
                        path to executable that is to be called before an
                        attempt is made to acquire a lock, where the lock key
                        is passed as the first argument. Any failures of this
                        executable are ignored
  --on-already-locked ON_ALREADY_LOCKED [ON_ALREADY_LOCKED ...]
                        path to executable that is to be called after an
                        attempt has been made to acquire a lock but failed due
                        to the lock already been taken, where the lock key is
                        passed as the first argument. Any failures of this
                        executable are ignored
  -i I                  number of seconds between polls to acquire a locked
                        lock

Examples

Acquire lock

Block until acquires lock with key "my/lock", which will expire after 10 minutes:

$ consul-lock lock --session-ttl=600 my/lock
{"created": "2017-11-30T14:55:49.322108", "key": "my/lock", "secondsToLock": 2.6241003070026636e-05, "session": "9b92744f-f1a9-db12-7873-ad44af5ae224"}
$ echo $?
0 

Try to acquire already locked "my/lock" but do not block:

$ consul-lock lock --non-blocking my/lock
null
Unable to acquire lock: my/lock
$ echo $?
100

(where null is the JSON output, written to stdout)

Add metadata to lock
$ consul-lock lock --metadata={"testing": 123} my/lock
{"created": "2017-12-05T12:26:13.717995", "key": "my/lock", "metadata": {"testing": 123}, "secondsToLock": 4.327880731027108, "session": "6ad662de-6e0c-8e0f-d92c-5fface60c49b"}
Acquire lock with event listeners
$ consul-lock lock --on-before-lock=./my-before-script.sh --on-already-locked=./my-locked-script.sh my/lock
{"created": "2017-12-07T13:02:06.773088", "key": "my/lock", "secondsToLock": 1.349498052150011e-05, "session": "459266be-2a85-464e-aa08-eda97613a29c"}

Note: if specifying event listeners in the form --x y, you will need to explicitly declare the end of the command options with a double dash, e.g. consul-lock lock --on-before-lock ./my-before-script.sh -- my/lock.

Unlock lock
$ consul-lock unlock my/lock
["my/lock"]
$ echo $?
0
Execute shell with lock
$ consul-lock execute my/lock ./my-executable
I am printed in "my-executable"

Note: the return code is the result of the executable

Python

from typing import Dict
from consullock.configuration import get_consul_configuration_from_environment
from consullock.managers import ConsulLockManager
from consullock.models import ConsulLockInformation

# Instantiate lock manager
lock_manager = ConsulLockManager(
    consul_configuration=get_consul_configuration_from_environment(),
    session_ttl_in_seconds=3600)
# Note: if the Consul configuration is not specified explicitly, an attempt to gather it from environmental variables 
# will be made (see: https://www.consul.io/docs/commands/index.html#environment-variables).

# Use lock in context
with lock_manager.acquire("my/lock"):
    do_things_holding_lock()

# Get lock
lock = lock_manager.acquire("my/lock", timeout=60, blocking=True, metadata="testing")

# Find lock associated to a given key
lock = lock_manager.find("my/lock")

# Find locks that match a regex
locks = lock_manager.find_regex("my/.*")  # type: Dict[str, Optional[ConsulLockInformation]]

# Release single lock
lock_manager.release("my/lock")

# Release many locks
lock_manager.release_all("my/lock-1", "my/lock-2", "my/lock-3")

# Release locks with key matching regex
lock_manager.release_regex("my/.*")

# Execute shell whilst holding lock (note: use context manager if executing Python!)
lock_manager.execute("my/lock", "echo Hello World")

Development

Tests

Prerequisites:

  • Docker (used to start Consul instances)

Install the test requirements:

pip install -r test_requirements.txt

Run tests with:

PYTHONPATH=. python -m unittest discover -v -s consullock/tests

Alternatives

consul-lock's People

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

logan2211

consul-lock's Issues

Session keepalive & lost locks

How to keep the session alive for locks that are held for a long time? How to best handle a lost lock, while doing something? Does this library solve these problems?

Support for Python <3.6

hello, I can't install your library with provided instructions. Error message is as follows:

$ pip install git+https://github.com/wtsi-hgi/consul-lock.git@master#egg=consullock
Collecting consullock from git+https://github.com/wtsi-hgi/consul-lock.git@master#egg=consullock
  Cloning https://github.com/wtsi-hgi/consul-lock.git (to master) to /tmp/pip-build-vnsw93ha/consullock

    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-vnsw93ha/consullock/setup.py", line 24
        f"{EXECUTABLE_NAME}=consullock.cli:entrypoint"
                                                     ^
    SyntaxError: invalid syntax

Any help would be appreciated a lot.

demjson dependency install fails when setuptools >58.0.0 is used

consullock dependency demjson fails to install on environments with setuptools>58.0.0.

demjson released a new demjson3 package to address this problem https://pypi.org/project/demjson3

Issue is discussed further here dmeranda/demjson#40

# test/bin/pip install consullock==4.2.0
Collecting consullock==4.2.0
  Using cached consullock-4.2.0.tar.gz (22 kB)
Collecting python-consul>=0.7.2
  Using cached python_consul-1.1.0-py2.py3-none-any.whl (24 kB)
Collecting timeout-decorator>=0.4.0
  Using cached timeout_decorator-0.5.0-py3-none-any.whl
Collecting hgijson>=1.5.0
  Using cached hgijson-3.1.0-py3-none-any.whl
Collecting demjson>=2.2.4
  Using cached demjson-2.2.4.tar.gz (131 kB)
    ERROR: Command errored out with exit status 1:
     command: /root/test/bin/python3.6 -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-ehoy4k_d/demjson_adfed282b286487089d7157d50aedcba/setup.py'"'"'; __file__='"'"'/tmp/pip-install-ehoy4k_d/demjson_adfed282b286487089d7157d50aedcba/setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(__file__) if os.path.exists(__file__) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-pip-egg-info-w0ym6tv2
         cwd: /tmp/pip-install-ehoy4k_d/demjson_adfed282b286487089d7157d50aedcba/
    Complete output (1 lines):
    error in demjson setup command: use_2to3 is invalid.
    ----------------------------------------
WARNING: Discarding https://files.pythonhosted.org/packages/96/67/6db789e2533158963d4af689f961b644ddd9200615b8ce92d6cad695c65a/demjson-2.2.4.tar.gz#sha256=31de2038a0fdd9c4c11f8bf3b13fe77bc2a128307f965c8d5fb4dc6d6f6beb79 (from https://pypi.org/simple/demjson/). Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
ERROR: Could not find a version that satisfies the requirement demjson>=2.2.4 (from consullock) (from versions: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 2.0, 2.0.1, 2.2, 2.2.1, 2.2.2, 2.2.3, 2.2.4)
ERROR: No matching distribution found for demjson>=2.2.4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.