apt: add policy_rc_d option (#47191)

This commit is contained in:
tchernomax 2018-11-19 15:45:48 +01:00 committed by John R Barker
parent 50808ffa8f
commit 943edb3319
2 changed files with 164 additions and 5 deletions

View file

@ -109,6 +109,15 @@ options:
type: bool
default: 'no'
version_added: "2.4"
policy_rc_d:
description:
- Force the exit code of /usr/sbin/policy-rc.d.
- For example, if I(policy_rc_d=101) the installed package will not trigger a service start.
- If /usr/sbin/policy-rc.d already exist, it is backed up and restored after the package installation.
- If C(null), the /usr/sbin/policy-rc.d isn't created/changed.
type: int
default: null
version_added: "2.8"
only_upgrade:
description:
- Only upgrade a package if it is already installed.
@ -261,8 +270,10 @@ import datetime
import fnmatch
import itertools
import os
import shutil
import re
import sys
import tempfile
import time
from ansible.module_utils.basic import AnsibleModule
@ -309,6 +320,83 @@ else:
PYTHON_APT = 'python3-apt'
class PolicyRcD(object):
"""
This class is a context manager for the /usr/sbin/policy-rc.d file.
It allow the user to prevent dpkg to start the corresponding service when installing
a package.
https://people.debian.org/~hmh/invokerc.d-policyrc.d-specification.txt
"""
def __init__(self, module):
# we need the module for later use (eg. fail_json)
self.m = module
# if policy_rc_d is null then we don't need to modify policy-rc.d
if self.m.params['policy_rc_d'] is None:
return
# if the /usr/sbin/policy-rc.d already exist
# we will back it up during package installation
# then restore it
if os.path.exists('/usr/sbin/policy-rc.d'):
self.backup_dir = tempfile.mkdtemp(prefix="ansible")
else:
self.backup_dir = None
def __enter__(self):
"""
This method will be call when we enter the context, before we call `apt-get `
"""
# if policy_rc_d is null then we don't need to modify policy-rc.d
if self.m.params['policy_rc_d'] is None:
return
# if the /usr/sbin/policy-rc.d already exist we back it up
if self.backup_dir:
try:
shutil.move('/usr/sbin/policy-rc.d', self.backup_dir)
except:
self.m.fail_json(msg="Fail to move /usr/sbin/policy-rc.d to %s" % self.backup_dir)
# we write /usr/sbin/policy-rc.d so it always exit with code policy_rc_d
try:
with open('/usr/sbin/policy-rc.d', 'w') as policy_rc_d:
policy_rc_d.write('#!/bin/sh\nexit %d\n' % self.m.params['policy_rc_d'])
os.chmod('/usr/sbin/policy-rc.d', 0o0755)
except:
self.m.fail_json(msg="Failed to create or chmod /usr/sbin/policy-rc.d")
def __exit__(self, type, value, traceback):
"""
This method will be call when we enter the context, before we call `apt-get `
"""
# if policy_rc_d is null then we don't need to modify policy-rc.d
if self.m.params['policy_rc_d'] is None:
return
if self.backup_dir:
# if /usr/sbin/policy-rc.d already exists before the call to __enter__
# we restore it (from the backup done in __enter__)
try:
shutil.move(os.path.join(self.backup_dir, 'policy-rc.d'),
'/usr/sbin/policy-rc.d')
os.rmdir(self.tmpdir_name)
except:
self.m.fail_json(msg="Fail to move back %s to /usr/sbin/policy-rc.d"
% os.path.join(self.backup_dir, 'policy-rc.d'))
else:
# if they wheren't any /usr/sbin/policy-rc.d file before the call to __enter__
# we just remove the file
try:
os.remove('/usr/sbin/policy-rc.d')
except:
self.m.fail_json(msg="Fail to remove /usr/sbin/policy-rc.d (after package manipulation)")
def package_split(pkgspec):
parts = pkgspec.split('=', 1)
version = None
@ -585,7 +673,9 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None,
if allow_unauthenticated:
cmd += " --allow-unauthenticated"
rc, out, err = m.run_command(cmd)
with PolicyRcD(m):
rc, out, err = m.run_command(cmd)
if m._diff:
diff = parse_diff(out)
else:
@ -674,7 +764,10 @@ def install_deb(m, debs, cache, force, install_recommends, allow_unauthenticated
options += " --force-all"
cmd = "dpkg %s -i %s" % (options, " ".join(pkgs_to_install))
rc, out, err = m.run_command(cmd)
with PolicyRcD(m):
rc, out, err = m.run_command(cmd)
if "stdout" in retvals:
stdout = retvals["stdout"] + out
else:
@ -734,7 +827,9 @@ def remove(m, pkgspec, cache, purge=False, force=False,
cmd = "%s -q -y %s %s %s %s %s remove %s" % (APT_GET_CMD, dpkg_options, purge, force_yes, autoremove, check_arg, packages)
rc, out, err = m.run_command(cmd)
with PolicyRcD(m):
rc, out, err = m.run_command(cmd)
if m._diff:
diff = parse_diff(out)
else:
@ -767,7 +862,9 @@ def cleanup(m, purge=False, force=False, operation=None,
cmd = "%s -y %s %s %s %s %s" % (APT_GET_CMD, dpkg_options, purge, force_yes, operation, check_arg)
rc, out, err = m.run_command(cmd)
with PolicyRcD(m):
rc, out, err = m.run_command(cmd)
if m._diff:
diff = parse_diff(out)
else:
@ -840,7 +937,9 @@ def upgrade(m, mode="yes", force=False, default_release=None,
if default_release:
cmd += " -t '%s'" % (default_release,)
rc, out, err = m.run_command(cmd, prompt_regex=prompt_regex)
with PolicyRcD(m):
rc, out, err = m.run_command(cmd, prompt_regex=prompt_regex)
if m._diff:
diff = parse_diff(out)
else:
@ -917,6 +1016,7 @@ def main():
dpkg_options=dict(type='str', default=DPKG_OPTIONS),
autoremove=dict(type='bool', default=False),
autoclean=dict(type='bool', default=False),
policy_rc_d=dict(type='int', default=None),
only_upgrade=dict(type='bool', default=False),
force_apt_get=dict(type='bool', default=False),
allow_unauthenticated=dict(type='bool', default=False, aliases=['allow-unauthenticated']),

View file

@ -258,3 +258,62 @@
assert:
that:
- apt_result is not changed
# check policy_rc_d parameter
- name: Install unscd but forbid service start
apt:
name: unscd
policy_rc_d: 101
- name: Stop unscd service
service:
name: unscd
state: stopped
register: service_unscd_stop
- name: unscd service shouldn't have been stopped by previous task
assert:
that: service_unscd_stop is not changed
- name: Uninstall unscd
apt:
name: unscd
policy_rc_d: 101
- name: Create incorrect /usr/sbin/policy-rc.d
copy:
dest: /usr/sbin/policy-rc.d
content: apt integration test
mode: 0755
- name: Install unscd but forbid service start
apt:
name: unscd
policy_rc_d: 101
- name: Stop unscd service
service:
name: unscd
state: stopped
register: service_unscd_stop
- name: unscd service shouldn't have been stopped by previous task
assert:
that: service_unscd_stop is not changed
- name: Create incorrect /usr/sbin/policy-rc.d
copy:
dest: /usr/sbin/policy-rc.d
content: apt integration test
mode: 0755
register: policy_rc_d
- name: Check if /usr/sbin/policy-rc.d was correctly backed-up during unscd install
assert:
that: policy_rc_d is not changed
- name: Delete /usr/sbin/policy-rc.d
file:
path: /usr/sbin/policy-rc.d
state: absent