Skip to main content

Cluster-wide Proxmox pmxcfs locks

Project description

pmxlock

Python classes and CLI tools for cluster-wide Proxmox pmxcfs locks.

Installation

Use pip for install:

pip install pmxlock

CLI usage

Start simple command:

pmxlock mylockname echo hello

or

python3 -m pmxlock mylockname echo hello

Only one command with mylockname lock can run in current time in cluster. Other commands will be blocked until current command completes.

You can exit with failure code instead of blocking. Use -n flag for nonblocking mode. Failure exit code is 1 by default. Use -E flag for other failure code:

pmxlock -n -E2 mylockname echo hello

Command above exits with code 2 if mylockname already acquired.

You can use timeout mode also:

pmxlock -w10 mylockname echo hello

Command above waits no more than 10 seconds and exits with code 1 if mylockname cannot be acquired.

If command has options use -- before command in order stop options parsing by pmxlock:

pmxlock mylockname -- echo -n hello

For mylockname-lock pmxlock uses node-wide /run/lock/pmxlock/mylockname flock and cluster-wide /etc/pve/priv/lock/mylockname pmxcfs-lock. If pmxlock terminated abnormaly (e.g. SIGKILL) /etc/pve/priv/lock/mylockname pmxcfs-lock will remain locked for pmxcfs timeout period (currently 120 seconds hardcoded in Proxmox). Other process on the same node can acquire orphaned lock without waiting. You can use pmxlock-gc cli command for clean all orphaned locks on current node.

pmxlock-gc

or

python3 -m pmxlock.gc

Class usage

Cluster-wide lock implemented by ClusterLock class:

from pmxlock import ClusterLock

lock = ClusterLock("mylockname")

Short operation in blocking mode:

lock.acquire()
try:
    # Your operation should be short or timeouted.
    # Hardcoded proxmox timeout == 120 seconds.
    # Take overheads into account and use shorter timeout 
    do_work(timeout=0.8 * 120) 
finally:
    lock.release()

ClusterLock lock implements context manager protocol for blocking mode:

with ClusterLock("mylockname"):
    do_work(timeout=0.8 * 120)

For long operations you need to use lock.update() regularly. You can use subprocess for it:

import subprocess

with ClusterLock("mylockname") as lock:
    proc = subprocess.Popen(command)
    while True:
        try:
            proc.wait(0.8 * 120)
            break
        except subprocess.TimeoutExpired:
            lock.update()

You can start operation in nonblocking mode:

if lock.acquire(blocking=False):
    try:
        do_work()
    finally:
        lock.release()
else:
    cannot_acquire_lock()

And timeout mode:

if lock.acquire(timeout=10):
    try:
        do_work()
    finally:
        lock.release()
else:
    cannot_acquire_lock()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pmxlock-1.1.0.tar.gz (23.1 kB view hashes)

Uploaded Source

Built Distribution

pmxlock-1.1.0-py3-none-any.whl (18.4 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page