159
158
'to utils.execute: %r') % kwargs)
162
cmd = shlex.split(FLAGS.root_helper) + list(cmd)
162
if FLAGS.rootwrap_config is None or FLAGS.root_helper != 'sudo':
163
deprecated.warn(_('The root_helper option (which lets you specify '
164
'a root wrapper different from nova-rootwrap, '
165
'and defaults to using sudo) is now deprecated. '
166
'You should use the rootwrap_config option '
169
if (FLAGS.rootwrap_config is not None):
170
cmd = ['sudo', 'nova-rootwrap', FLAGS.rootwrap_config] + list(cmd)
172
cmd = shlex.split(FLAGS.root_helper) + list(cmd)
163
173
cmd = map(str, cmd)
165
175
while attempts > 0:
572
class GreenLockFile(lockfile.FileLock):
573
"""Implementation of lockfile that allows for a lock per greenthread.
575
Simply implements lockfile:LockBase init with an addiontall suffix
576
on the unique name of the greenthread identifier
585
class _InterProcessLock(object):
586
"""Lock implementation which allows multiple locks, working around
587
issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does
588
not require any cleanup. Since the lock is always held on a file
589
descriptor rather than outside of the process, the lock gets dropped
590
automatically if the process crashes, even if __exit__ is not executed.
592
There are no guarantees regarding usage by multiple green threads in a
593
single process here. This lock works only between processes. Exclusive
594
access between local threads should be achieved using the semaphores
595
in the @synchronized decorator.
597
Note these locks are released when the descriptor is closed, so it's not
598
safe to close the file descriptor while another green thread holds the
599
lock. Just opening and closing the lock file can break synchronisation,
600
so lock files must be accessed only using this abstraction.
578
def __init__(self, path, threaded=True):
580
self.lock_file = os.path.abspath(path) + ".lock"
581
self.hostname = socket.gethostname()
582
self.pid = os.getpid()
584
t = threading.current_thread()
585
# Thread objects in Python 2.4 and earlier do not have ident
586
# attrs. Worm around that.
587
ident = getattr(t, "ident", hash(t)) or hash(t)
588
gident = corolocal.get_ident()
589
self.tname = "-%x-%x" % (ident & 0xffffffff, gident & 0xffffffff)
592
dirname = os.path.dirname(self.lock_file)
593
self.unique_name = os.path.join(dirname,
594
"%s%s.%s" % (self.hostname,
603
def __init__(self, name):
608
self.lockfile = open(self.fname, 'w')
612
# Using non-blocking locks since green threads are not
613
# patched to deal with blocking locking calls.
614
# Also upon reading the MSDN docs for locking(), it seems
615
# to have a laughable 10 attempts "blocking" mechanism.
619
if e.errno in (errno.EACCES, errno.EAGAIN):
620
# external locks synchronise things like iptables
621
# updates - give it some time to prevent busy spinning
626
def __exit__(self, exc_type, exc_val, exc_tb):
629
self.lockfile.close()
631
LOG.exception(_("Could not release the aquired lock `%s`")
635
raise NotImplementedError()
638
raise NotImplementedError()
641
class _WindowsLock(_InterProcessLock):
643
msvcrt.locking(self.lockfile, msvcrt.LK_NBLCK, 1)
646
msvcrt.locking(self.lockfile, msvcrt.LK_UNLCK, 1)
649
class _PosixLock(_InterProcessLock):
651
fcntl.lockf(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB)
654
fcntl.lockf(self.lockfile, fcntl.LOCK_UN)
659
InterProcessLock = _WindowsLock
662
InterProcessLock = _PosixLock
664
_semaphores = weakref.WeakValueDictionary()
602
667
def synchronized(name, external=False):
648
699
# NOTE(soren): If we ever go natively threaded, this will be racy.
649
700
# See http://stackoverflow.com/questions/5390569/dyn
650
701
# amically-allocating-and-destroying-mutexes
702
sem = _semaphores.get(name, semaphore.Semaphore())
651
703
if name not in _semaphores:
652
_semaphores[name] = semaphore.Semaphore()
653
sem = _semaphores[name]
704
# this check is not racy - we're already holding ref locally
705
# so GC won't remove the item and there was no IO switch
706
# (only valid in greenthreads)
707
_semaphores[name] = sem
654
709
LOG.debug(_('Attempting to grab semaphore "%(lock)s" for method '
655
710
'"%(method)s"...'), {'lock': name,
656
711
'method': f.__name__})
674
729
retval = f(*args, **kwargs)
676
# If no-one else is waiting for it, delete it.
677
# See note about possible raciness above.
678
if not sem.balance < 1:
679
del _semaphores[name]
686
def cleanup_file_locks():
687
"""clean up stale locks left behind by process failures
689
The lockfile module, used by @synchronized, can leave stale lockfiles
690
behind after process failure. These locks can cause process hangs
691
at startup, when a process deadlocks on a lock which will never
694
Intended to be called at service startup.
698
# NOTE(mikeyp) this routine incorporates some internal knowledge
699
# from the lockfile module, and this logic really
700
# should be part of that module.
703
# 1) look for the lockfile modules's 'sentinel' files, of the form
704
# hostname.[thread-.*]-pid, extract the pid.
705
# if pid doesn't match a running process, delete the file since
706
# it's from a dead process.
707
# 2) check for the actual lockfiles. if lockfile exists with linkcount
708
# of 1, it's bogus, so delete it. A link count >= 2 indicates that
709
# there are probably sentinels still linked to it from active
710
# processes. This check isn't perfect, but there is no way to
711
# reliably tell which sentinels refer to which lock in the
712
# lockfile implementation.
714
if FLAGS.disable_process_locking:
717
hostname = socket.gethostname()
718
sentinel_re = hostname + r'\..*-(\d+$)'
719
lockfile_re = r'nova-.*\.lock'
720
files = os.listdir(FLAGS.lock_path)
723
for filename in files:
724
match = re.match(sentinel_re, filename)
728
LOG.debug(_('Found sentinel %(filename)s for pid %(pid)s'),
729
{'filename': filename, 'pid': pid})
734
delete_if_exists(os.path.join(FLAGS.lock_path, filename))
735
LOG.debug(_('Cleaned sentinel %(filename)s for pid %(pid)s'),
736
{'filename': filename, 'pid': pid})
739
for filename in files:
740
match = re.match(lockfile_re, filename)
744
stat_info = os.stat(os.path.join(FLAGS.lock_path, filename))
746
if e.errno == errno.ENOENT:
750
LOG.debug(_('Found lockfile %(file)s with link count %(count)d'),
751
{'file': filename, 'count': stat_info.st_nlink})
752
if stat_info.st_nlink == 1:
753
delete_if_exists(os.path.join(FLAGS.lock_path, filename))
754
LOG.debug(_('Cleaned lockfile %(file)s with link count %(count)d'),
755
{'file': filename, 'count': stat_info.st_nlink})
758
736
def delete_if_exists(pathname):
759
737
"""delete a file, but ignore file not found error"""
837
def diff_dict(orig, new):
839
Return a dict describing how to change orig to new. The keys
840
correspond to values that have changed; the value will be a list
841
of one or two elements. The first element of the list will be
842
either '+' or '-', indicating whether the key was updated or
843
deleted; if the key was updated, the list will contain a second
844
element, giving the updated value.
846
# Figure out what keys went away
847
result = dict((k, ['-']) for k in set(orig.keys()) - set(new.keys()))
848
# Compute the updates
849
for key, value in new.items():
850
if key not in orig or value != orig[key]:
851
result[key] = ['+', value]
859
855
def check_isinstance(obj, cls):
860
856
"""Checks that obj is of type cls, and lets PyLint infer types."""
861
857
if isinstance(obj, cls):
1233
def walk_class_hierarchy(clazz, encountered=None):
1234
"""Walk class hierarchy, yielding most derived classes first"""
1237
for subclass in clazz.__subclasses__():
1238
if subclass not in encountered:
1239
encountered.append(subclass)
1240
# drill down to leaves first
1241
for subsubclass in walk_class_hierarchy(subclass, encountered):
1236
1246
class UndoManager(object):
1237
1247
"""Provides a mechanism to facilitate rolling back a series of actions
1238
1248
when an exception is raised.