yum: take care of stale/invalid yum.pid (#58457)
* yum: take care of stale/invalid yum.pid * Add changelog
This commit is contained in:
parent
939e2b4c79
commit
5064e67d37
6 changed files with 96 additions and 7 deletions
2
changelogs/fragments/yum-handle-stale-lock-file.yaml
Normal file
2
changelogs/fragments/yum-handle-stale-lock-file.yaml
Normal file
|
@ -0,0 +1,2 @@
|
|||
bugfixes:
|
||||
- yum - handle stale/invalid yum.pid lock file (https://github.com/ansible/ansible/issues/57189)
|
|
@ -126,15 +126,25 @@ class YumDnf(with_metaclass(ABCMeta, object)):
|
|||
# default isn't a bad idea
|
||||
self.lockfile = '/var/run/yum.pid'
|
||||
|
||||
def is_lockfile_pid_valid(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def _is_lockfile_present(self):
|
||||
return (os.path.isfile(self.lockfile) or glob.glob(self.lockfile)) and self.is_lockfile_pid_valid()
|
||||
|
||||
def wait_for_lock(self):
|
||||
'''Poll until the lock is removed if timeout is a positive number'''
|
||||
if (os.path.isfile(self.lockfile) or glob.glob(self.lockfile)):
|
||||
if self.lock_timeout > 0:
|
||||
for iteration in range(0, self.lock_timeout):
|
||||
time.sleep(1)
|
||||
if not os.path.isfile(self.lockfile) and not glob.glob(self.lockfile):
|
||||
return
|
||||
self.module.fail_json(msg='{0} lockfile is held by another process'.format(self.pkg_mgr_name))
|
||||
|
||||
if not self._is_lockfile_present():
|
||||
return
|
||||
|
||||
if self.lock_timeout > 0:
|
||||
for iteration in range(0, self.lock_timeout):
|
||||
time.sleep(1)
|
||||
if not self._is_lockfile_present():
|
||||
return
|
||||
|
||||
self.module.fail_json(msg='{0} lockfile is held by another process'.format(self.pkg_mgr_name))
|
||||
|
||||
def listify_comma_sep_strings_in_list(self, some_list):
|
||||
"""
|
||||
|
|
|
@ -329,6 +329,11 @@ class DnfModule(YumDnf):
|
|||
except AttributeError:
|
||||
self.with_modules = False
|
||||
|
||||
def is_lockfile_pid_valid(self):
|
||||
# FIXME? it looks like DNF takes care of invalid lock files itself?
|
||||
# https://github.com/ansible/ansible/issues/57189
|
||||
return True
|
||||
|
||||
def _sanitize_dnf_error_msg(self, spec, error):
|
||||
"""
|
||||
For unhandled dnf.exceptions.Error scenarios, there are certain error
|
||||
|
|
|
@ -336,6 +336,7 @@ from ansible.module_utils._text import to_native, to_text
|
|||
from ansible.module_utils.urls import fetch_url
|
||||
from ansible.module_utils.yumdnf import YumDnf, yumdnf_argument_spec
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
|
@ -410,6 +411,44 @@ class YumModule(YumDnf):
|
|||
else:
|
||||
raise e
|
||||
|
||||
def is_lockfile_pid_valid(self):
|
||||
try:
|
||||
with open(self.lockfile, 'r') as f:
|
||||
oldpid = int(f.readline())
|
||||
except ValueError:
|
||||
# invalid data
|
||||
os.unlink(self.lockfile)
|
||||
return False
|
||||
except (IOError, OSError) as e:
|
||||
self.module.fail_json(msg="Failure opening %s: %s" % (self.lockfile, to_native(e)))
|
||||
|
||||
if oldpid == os.getpid():
|
||||
# that's us?
|
||||
os.unlink(self.lockfile)
|
||||
return False
|
||||
|
||||
try:
|
||||
with open("/proc/%d/stat" % oldpid, 'r') as f:
|
||||
stat = f.readline()
|
||||
|
||||
if stat.split()[2] == 'Z':
|
||||
# Zombie
|
||||
os.unlink(self.lockfile)
|
||||
return False
|
||||
except IOError:
|
||||
try:
|
||||
os.kill(oldpid, 0)
|
||||
except OSError as e:
|
||||
if e.errno == errno.ESRCH:
|
||||
# No such process
|
||||
os.unlink(self.lockfile)
|
||||
return False
|
||||
|
||||
self.module.fail_json(msg="Unable to check PID %s in %s: %s" % (oldpid, self.lockfile, to_native(e)))
|
||||
|
||||
# another copy seems to be running
|
||||
return True
|
||||
|
||||
def yum_base(self):
|
||||
my = yum.YumBase()
|
||||
my.preconf.debuglevel = 0
|
||||
|
|
28
test/integration/targets/yum/tasks/lock.yml
Normal file
28
test/integration/targets/yum/tasks/lock.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
- block:
|
||||
- name: Make sure testing package is not installed
|
||||
yum:
|
||||
name: sos
|
||||
state: absent
|
||||
|
||||
- name: Create bogus lock file
|
||||
copy:
|
||||
content: bogus content for this lock file
|
||||
dest: /var/run/yum.pid
|
||||
|
||||
- name: Install a package, lock file should be deleted by the module
|
||||
yum:
|
||||
name: sos
|
||||
state: present
|
||||
register: yum_result
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- yum_result is success
|
||||
|
||||
always:
|
||||
- name: Clean up
|
||||
yum:
|
||||
name: sos
|
||||
state: absent
|
||||
|
||||
when: ansible_pkg_mgr == 'yum'
|
|
@ -60,3 +60,8 @@
|
|||
- import_tasks: check_mode_consistency.yml
|
||||
when:
|
||||
- (ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux'] and ansible_distribution_major_version|int == 7)
|
||||
|
||||
|
||||
- import_tasks: lock.yml
|
||||
when:
|
||||
- ansible_distribution in ['RedHat', 'CentOS', 'ScientificLinux']
|
||||
|
|
Loading…
Reference in a new issue