-
-
Save mcansky/07a86eab5213dcf80e46 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
''' | |
Check that apt lock is off or on. If on, wait up to 60 seconds before trying | |
again and returning success (if released) or failure. | |
Author: Thomas R. R. Riboulet <[email protected]> | |
''' | |
import logging | |
import json | |
import time | |
import fcntl | |
# Set up logging | |
LOG = logging.getLogger(__name__) | |
def _apt_locked(): | |
''' | |
Try locking the apt lock | |
True if locked | |
False if unlocked | |
''' | |
with open('/var/lib/dpkg/lock', 'w') as handle: | |
try: | |
fcntl.lockf(handle, fcntl.LOCK_EX | fcntl.LOCK_NB) | |
return False | |
except IOError: | |
return True | |
def check_lock(): | |
''' | |
Check lock state and return success if it's free or released under 60 seconds | |
''' | |
if _apt_locked(): | |
LOG.info("APT lock ON, waiting 60 seconds") | |
time.sleep(60) | |
if _apt_locked(): | |
LOG.info("APT lock still ON, exiting") | |
return False | |
LOG.info("APT lock OFF") | |
return True | |
if __name__ == "__main__": | |
print check_lock() |
Ah, parameter adding was very easy, now also with comment which shows waiting time/retries:
--- base/_modules/apt_lock_wait.py.orig 2016-02-12 19:34:07.292498856 +0000
+++ base/_modules/apt_lock_wait.py 2016-02-14 12:59:22.519371134 +0000
@@ -1,8 +1,8 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
-Check that apt lock is off or on. If on, wait up to 60 seconds before trying
-again and returning success (if released) or failure.
+Check that apt lock is off or on. If on, wait up to 10 times 2 seconds before trying
+again and returning success (if released) or failure after last check.
Author: Thomas R. R. Riboulet <[email protected]>
@@ -29,19 +29,34 @@
except IOError:
return True
-def check_lock():
+def check_lock(name='check_apt_lock', retries=10, timeout=2):
'''
- Check lock state and return success if it's free or released under 60 seconds
+ Check lock state and return success if it's free or released under timeout=2 seconds
'''
- if _apt_locked():
- LOG.info("APT lock ON, waiting 60 seconds")
- time.sleep(60)
- if _apt_locked():
- LOG.info("APT lock still ON, exiting")
- return False
+ ret = {'name': name, 'result': False, 'comment': ''}
- LOG.info("APT lock OFF")
- return True
+ count = 0
+ while count < retries and _apt_locked():
+ LOG.info('APT lock ON, waiting {0} seconds (#{1})'.format(timeout, count))
+ time.sleep(timeout)
+ count += 1
+
+ if count >= retries and _apt_locked():
+ LOG.info('APT lock ON, exiting after {0} seconds (#{1})'.format(timeout*count, count))
+ ret['result'] = False
+ ret['comment'] = 'APT lock ON, exiting after {0} seconds (#{1})'.format(timeout*count, count)
+ return ret
+
+ if count > 0:
+ LOG.info('APT lock OFF, exiting after {0} seconds (#{1})'.format(timeout*count, count))
+ ret['result'] = True
+ ret['comment'] = 'APT lock OFF, exiting after {0} seconds (#{1})'.format(timeout*count, count)
+ return ret
+
+ LOG.info('APT lock OFF')
+ ret['result'] = True
+ ret['comment'] = 'APT lock OFF'
+ return ret
if __name__ == "__main__":
print check_lock()
One "big" problem is still left: the state is always run as "changed" when defined this way:
jenkins-package:
module.run:
- name: apt_lock_wait.check_lock
pkg.installed:
- name: jenkins
But it seems that this can only changed by having another module type:
From last answer in: http://grokbase.com/t/gg/salt-users/14b6rzhwzb/calling-an-execution-module-results-in-changed-everytime
What you really want to look into is using a custom state module, instead of a custom execution module. You then have full control over the return data structure.
More info here: http://docs.saltstack.com/en/latest/ref/states/writing.html
Or can this module called differently ?
EDIT: easy solution: creating an onlyif condition runs the module only if locks exists
jenkins-package:
module.run:
- name: apt_lock_wait.check_lock
- onlyif: test -n "$(lslocks -r -o PATH | grep /var/lib/dpkg/lock)"
pkg.installed:
- name: jenkins
Seems some kernel/other package updates broke something with lslocks so it took very long to check:
# time (lslocks -r -o PATH | grep /var/lib/dpkg/lock)
real 0m16.080s
user 0m0.976s
sys 0m15.104s
A nice solution I found is checking it with lsof instead:
# time (lsof | grep -q /var/lib/dpkg/lock)
real 0m2.715s
user 0m1.364s
sys 0m1.184s
but for this the package has to be installed first.
So I decided to put two different checks before which programs are setup by default:
- test (from bash/shell) to see if lockfile exists
- fuser to check if a program is accessing it
jenkins-package:
module.run:
- name: apt_lock_wait.check_lock
- onlyif: test -f /var/lib/dpkg/lock && `fuser /var/lib/dpkg/lock >/dev/null 2>&1` && `lslocks -r -o PATH | grep -q /var/lib/dpkg/lock`
pkg.installed:
- name: jenkins
Here the patch which generates a nice loop around the check so we didn't fail hard at 2nd failed try
(if it make sense perhaps some is interested in making timeout and retries configurable by state):