def acquire(self): basedir = os.path.dirname(self.fname) if not os.path.exists(basedir): fileutils.ensure_tree(basedir) LOG.info(_LI('Created lock path: %s'), basedir) self.lockfile = open(self.fname, 'w') while True: try: # Using non-blocking locks since green threads are not # patched to deal with blocking locking calls. # Also upon reading the MSDN docs for locking(), it seems # to have a laughable 10 attempts "blocking" mechanism. self.trylock() LOG.debug('Got file lock "%s"', self.fname) return True except IOError as e: if e.errno in (errno.EACCES, errno.EAGAIN): # external locks synchronise things like iptables # updates - give it some time to prevent busy spinning time.sleep(0.01) else: raise threading.ThreadError(_("Unable to acquire lock on" " `%(filename)s` due to" " %(exception)s") % {'filename': self.fname, 'exception': e})
def create_iscsi_target(self, name, tid, lun, path, chap_auth=None, **kwargs): # Note(jdg) tid and lun aren't used by TgtAdm but remain for # compatibility fileutils.ensure_tree(self.volumes_dir) vol_id = name.split(':')[1] if chap_auth is None: volume_conf = self.VOLUME_CONF % (name, path) else: volume_conf = self.VOLUME_CONF_WITH_CHAP_AUTH % (name, path, chap_auth) LOG.info(_('Creating iscsi_target for: %s') % vol_id) volumes_dir = self.volumes_dir postfix = ".conf" volume_path = os.path.join(volumes_dir, vol_id) + postfix f = open(volume_path, 'w+') f.write(volume_conf) f.close() LOG.debug(_('Created volume path %(vp)s,\n' 'content: %(vc)s') % {'vp': volume_path, 'vc': volume_conf}) old_persist_file = None old_name = kwargs.get('old_name', None) if old_name is not None: old_persist_file = os.path.join(volumes_dir, old_name) try: # with the persistent tgts we create them # by creating the entry in the persist file # and then doing an update to get the target # created. (out, err) = self._execute('tgt-admin', '--update', name, run_as_root=True, root_helper=self._root_helper) LOG.debug("StdOut from tgt-admin --update: %s", out) LOG.debug("StdErr from tgt-admin --update: %s", err) # Grab targets list for debug # Consider adding a check for lun 0 and 1 for tgtadm # before considering this as valid (out, err) = self._execute('tgtadm', '--lld', 'iscsi', '--op', 'show', '--mode', 'target', run_as_root=True, root_helper=self._root_helper) LOG.debug("Targets after update: %s" % out) except putils.ProcessExecutionError as e: LOG.warning(_("Failed to create iscsi target for volume " "id:%(vol_id)s: %(e)s") % {'vol_id': vol_id, 'e': e}) #Don't forget to remove the persistent file we created os.unlink(volume_path) raise exception.ISCSITargetCreateFailed(volume_id=vol_id) iqn = '%s%s' % (self.iscsi_target_prefix, vol_id) tid = self._get_target(iqn) if tid is None: LOG.error(_("Failed to create iscsi target for volume " "id:%(vol_id)s. Please ensure your tgtd config file " "contains 'include %(volumes_dir)s/*'") % { 'vol_id': vol_id, 'volumes_dir': volumes_dir, }) raise exception.NotFound() # NOTE(jdg): Sometimes we have some issues with the backing lun # not being created, believe this is due to a device busy # or something related, so we're going to add some code # here that verifies the backing lun (lun 1) was created # and we'll try and recreate it if it's not there if not self._verify_backing_lun(iqn, tid): try: self._recreate_backing_lun(iqn, tid, name, path) except putils.ProcessExecutionError: os.unlink(volume_path) raise exception.ISCSITargetCreateFailed(volume_id=vol_id) # Finally check once more and if no go, fail and punt if not self._verify_backing_lun(iqn, tid): os.unlink(volume_path) raise exception.ISCSITargetCreateFailed(volume_id=vol_id) if old_persist_file is not None and os.path.exists(old_persist_file): os.unlink(old_persist_file) return tid
def lock(name, lock_file_prefix=None, external=False, lock_path=None): """Context based lock This function yields a `threading.Semaphore` instance (if we don't use eventlet.monkey_patch(), else `semaphore.Semaphore`) unless external is True, in which case, it'll yield an InterProcessLock instance. :param lock_file_prefix: The lock_file_prefix argument is used to provide lock files on disk with a meaningful prefix. :param external: The external keyword argument denotes whether this lock should work across multiple processes. This means that if two different workers both run a a method decorated with @synchronized('mylock', external=True), only one of them will execute at a time. :param lock_path: The lock_path keyword argument is used to specify a special location for external lock files to live. If nothing is set, then CONF.lock_path is used as a default. """ with _semaphores_lock: try: sem = _semaphores[name] except KeyError: sem = threading.Semaphore() _semaphores[name] = sem with sem: LOG.debug(_('Got semaphore "%(lock)s"'), {'lock': name}) # NOTE(mikal): I know this looks odd if not hasattr(local.strong_store, 'locks_held'): local.strong_store.locks_held = [] local.strong_store.locks_held.append(name) try: if external and not CONF.disable_process_locking: LOG.debug(_('Attempting to grab file lock "%(lock)s"'), {'lock': name}) # We need a copy of lock_path because it is non-local local_lock_path = lock_path or CONF.lock_path if not local_lock_path: raise cfg.RequiredOptError('lock_path') if not os.path.exists(local_lock_path): fileutils.ensure_tree(local_lock_path) LOG.info(_('Created lock path: %s'), local_lock_path) def add_prefix(name, prefix): if not prefix: return name sep = '' if prefix.endswith('-') else '-' return '%s%s%s' % (prefix, sep, name) # NOTE(mikal): the lock name cannot contain directory # separators lock_file_name = add_prefix(name.replace(os.sep, '_'), lock_file_prefix) lock_file_path = os.path.join(local_lock_path, lock_file_name) try: lock = InterProcessLock(lock_file_path) with lock as lock: LOG.debug(_('Got file lock "%(lock)s" at %(path)s'), {'lock': name, 'path': lock_file_path}) yield lock finally: LOG.debug(_('Released file lock "%(lock)s" at %(path)s'), {'lock': name, 'path': lock_file_path}) else: yield sem finally: local.strong_store.locks_held.remove(name)
def create_iscsi_target(self, name, tid, lun, path, chap_auth=None, **kwargs): # Note(jdg) tid and lun aren't used by TgtAdm but remain for # compatibility fileutils.ensure_tree(self.volumes_dir) vol_id = name.split(':')[1] write_cache = kwargs.get('write_cache', 'on') if chap_auth is None: volume_conf = self.VOLUME_CONF % (name, path, write_cache) else: volume_conf = self.VOLUME_CONF_WITH_CHAP_AUTH % (name, path, chap_auth, write_cache) LOG.info(_('Creating iscsi_target for: %s') % vol_id) volumes_dir = self.volumes_dir volume_path = os.path.join(volumes_dir, vol_id) f = open(volume_path, 'w+') f.write(volume_conf) f.close() LOG.debug('Created volume path %(vp)s,\n' 'content: %(vc)s' % {'vp': volume_path, 'vc': volume_conf}) old_persist_file = None old_name = kwargs.get('old_name', None) if old_name is not None: old_persist_file = os.path.join(volumes_dir, old_name) try: # with the persistent tgts we create them # by creating the entry in the persist file # and then doing an update to get the target # created. (out, err) = self._execute('tgt-admin', '--update', name, run_as_root=True) LOG.debug("StdOut from tgt-admin --update: %s", out) LOG.debug("StdErr from tgt-admin --update: %s", err) # Grab targets list for debug # Consider adding a check for lun 0 and 1 for tgtadm # before considering this as valid (out, err) = self._execute('tgtadm', '--lld', 'iscsi', '--op', 'show', '--mode', 'target', run_as_root=True) LOG.debug("Targets after update: %s" % out) except putils.ProcessExecutionError as e: LOG.warning(_("Failed to create iscsi target for volume " "id:%(vol_id)s: %(e)s") % {'vol_id': vol_id, 'e': e}) #Don't forget to remove the persistent file we created os.unlink(volume_path) raise exception.ISCSITargetCreateFailed(volume_id=vol_id) iqn = '%s%s' % (self.iscsi_target_prefix, vol_id) tid = self._get_target(iqn) if tid is None: LOG.error(_("Failed to create iscsi target for volume " "id:%(vol_id)s. Please ensure your tgtd config file " "contains 'include %(volumes_dir)s/*'") % { 'vol_id': vol_id, 'volumes_dir': volumes_dir, }) raise exception.NotFound() # NOTE(jdg): Sometimes we have some issues with the backing lun # not being created, believe this is due to a device busy # or something related, so we're going to add some code # here that verifies the backing lun (lun 1) was created # and we'll try and recreate it if it's not there if not self._verify_backing_lun(iqn, tid): try: self._recreate_backing_lun(iqn, tid, name, path) except putils.ProcessExecutionError: os.unlink(volume_path) raise exception.ISCSITargetCreateFailed(volume_id=vol_id) # Finally check once more and if no go, fail and punt if not self._verify_backing_lun(iqn, tid): os.unlink(volume_path) raise exception.ISCSITargetCreateFailed(volume_id=vol_id) if old_persist_file is not None and os.path.exists(old_persist_file): os.unlink(old_persist_file) return tid