apt: add policy_rc_d option (#47191)

pull/48882/head
tchernomax 6 years ago committed by John R Barker
parent 50808ffa8f
commit 943edb3319

@ -109,6 +109,15 @@ options:
type: bool type: bool
default: 'no' default: 'no'
version_added: "2.4" 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: only_upgrade:
description: description:
- Only upgrade a package if it is already installed. - Only upgrade a package if it is already installed.
@ -261,8 +270,10 @@ import datetime
import fnmatch import fnmatch
import itertools import itertools
import os import os
import shutil
import re import re
import sys import sys
import tempfile
import time import time
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
@ -309,6 +320,83 @@ else:
PYTHON_APT = 'python3-apt' 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): def package_split(pkgspec):
parts = pkgspec.split('=', 1) parts = pkgspec.split('=', 1)
version = None version = None
@ -585,7 +673,9 @@ def install(m, pkgspec, cache, upgrade=False, default_release=None,
if allow_unauthenticated: if allow_unauthenticated:
cmd += " --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: if m._diff:
diff = parse_diff(out) diff = parse_diff(out)
else: else:
@ -674,7 +764,10 @@ def install_deb(m, debs, cache, force, install_recommends, allow_unauthenticated
options += " --force-all" options += " --force-all"
cmd = "dpkg %s -i %s" % (options, " ".join(pkgs_to_install)) 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: if "stdout" in retvals:
stdout = retvals["stdout"] + out stdout = retvals["stdout"] + out
else: 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) 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: if m._diff:
diff = parse_diff(out) diff = parse_diff(out)
else: 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) 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: if m._diff:
diff = parse_diff(out) diff = parse_diff(out)
else: else:
@ -840,7 +937,9 @@ def upgrade(m, mode="yes", force=False, default_release=None,
if default_release: if default_release:
cmd += " -t '%s'" % (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: if m._diff:
diff = parse_diff(out) diff = parse_diff(out)
else: else:
@ -917,6 +1016,7 @@ def main():
dpkg_options=dict(type='str', default=DPKG_OPTIONS), dpkg_options=dict(type='str', default=DPKG_OPTIONS),
autoremove=dict(type='bool', default=False), autoremove=dict(type='bool', default=False),
autoclean=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), only_upgrade=dict(type='bool', default=False),
force_apt_get=dict(type='bool', default=False), force_apt_get=dict(type='bool', default=False),
allow_unauthenticated=dict(type='bool', default=False, aliases=['allow-unauthenticated']), allow_unauthenticated=dict(type='bool', default=False, aliases=['allow-unauthenticated']),

@ -258,3 +258,62 @@
assert: assert:
that: that:
- apt_result is not changed - 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

Loading…
Cancel
Save