175 lines
4.9 KiB
Plaintext
175 lines
4.9 KiB
Plaintext
|
#!/usr/bin/python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
"""
|
||
|
Ansible module for reconfiguring debian packages.
|
||
|
(c) 2013, Sebastien Bocahu <sebastien.bocahu@nuxit.com>
|
||
|
|
||
|
This file is part of Ansible
|
||
|
|
||
|
Ansible is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
Ansible is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||
|
"""
|
||
|
|
||
|
DOCUMENTATION = '''
|
||
|
---
|
||
|
module: dpkg_reconfigure
|
||
|
short_description: Reconfigure a Debian package.
|
||
|
description:
|
||
|
- Reconfigure a Debian package using dpkg-reconfigure.
|
||
|
version_added: "1.2"
|
||
|
notes:
|
||
|
- A number of questions has to be answered (depending on the package).
|
||
|
Use 'DEBIAN_FRONTED=editor dpkg-reconfigure $pkg' for finding them.
|
||
|
options:
|
||
|
pkg:
|
||
|
description:
|
||
|
- Package to configure.
|
||
|
required: true
|
||
|
default: null
|
||
|
aliases: []
|
||
|
answers:
|
||
|
description:
|
||
|
- Debconf configuration answer(s)/question(s).
|
||
|
required: true
|
||
|
default: null
|
||
|
aliases: []
|
||
|
author: Sebastien Bocahu
|
||
|
'''
|
||
|
|
||
|
EXAMPLES = '''
|
||
|
# Set default locale to fr_FR.UTF-8, and generate en_US.UTF-8 as well:
|
||
|
dpkg_reconfigure:
|
||
|
pkg: locales
|
||
|
answers:
|
||
|
locales/default_environment_locale: fr_FR.UTF-8
|
||
|
locales/locales_to_be_generated: en_US.UTF-8 UTF-8, fr_FR.UTF-8 UTF-8
|
||
|
|
||
|
# Reconfigure roundcube, using configuration answers stored in a file:
|
||
|
dpkg_reconfigure: pkg=roundcube answers='$FILE(/path/dpkg-reconfigure/roundcube)'"
|
||
|
'''
|
||
|
|
||
|
import sys
|
||
|
import os
|
||
|
import pwd
|
||
|
import os.path
|
||
|
import re
|
||
|
import tempfile
|
||
|
|
||
|
def get_selections(module, pkg):
|
||
|
cmd = [module.get_bin_path('debconf-show', True)]
|
||
|
cmd.append(' %s' % pkg)
|
||
|
rc, out, err = module.run_command(' '.join(cmd))
|
||
|
|
||
|
if rc == 0:
|
||
|
selections = {}
|
||
|
for answer in out.split('\n'):
|
||
|
item = re.search('^[* ] ([^:]+): (.*)$', answer)
|
||
|
if item:
|
||
|
value = item.group(2).strip()
|
||
|
if value == 'true':
|
||
|
value = 'yes'
|
||
|
elif value == 'false':
|
||
|
value = 'no'
|
||
|
selections[ item.group(1).strip() ] = value
|
||
|
return selections
|
||
|
else:
|
||
|
module.fail_json(msg=err)
|
||
|
|
||
|
|
||
|
def dpkg_reconfigure(module, pkg, wanted_config):
|
||
|
editor_script = [ '#!/bin/sh', 'sed -i "$1" -f - <<EOF' ]
|
||
|
for question in wanted_config:
|
||
|
e_question = re.sub(r'([\\/&])', r'\\\1', question)
|
||
|
e_answer = re.sub(r'([\\/&])', r'\\\1', wanted_config[question])
|
||
|
editor_script.append('s/^\\(%s\\)\\s*=.*/\\1="%s"/' % (e_question, e_answer))
|
||
|
editor_script.append('EOF')
|
||
|
|
||
|
outfd, outsock_path = tempfile.mkstemp()
|
||
|
tmp = os.fdopen(outfd,'w')
|
||
|
tmp.write('\n'.join(editor_script))
|
||
|
tmp.close()
|
||
|
os.chmod(outsock_path, stat.S_IEXEC)
|
||
|
|
||
|
cmd = [ 'EDITOR=%s DEBIAN_FRONTEND=editor' % outsock_path ]
|
||
|
cmd.append(module.get_bin_path('dpkg-reconfigure', True))
|
||
|
cmd.append(pkg)
|
||
|
rc, out, err = module.run_command(' '.join(cmd), use_unsafe_shell=True)
|
||
|
os.unlink(outsock_path)
|
||
|
|
||
|
if rc == 0:
|
||
|
return True, err
|
||
|
else:
|
||
|
return False, err
|
||
|
|
||
|
|
||
|
def enforce_state(module, params):
|
||
|
|
||
|
pkg = params["pkg"]
|
||
|
answers = params["answers"]
|
||
|
|
||
|
wanted_config = {}
|
||
|
|
||
|
if type(answers) is dict:
|
||
|
wanted_config = answers
|
||
|
else:
|
||
|
for answer in answers.split('\n'):
|
||
|
item = re.findall(r"[^\s]+", answer)
|
||
|
if len(item) > 1:
|
||
|
wanted_config[ item[0].strip() ] = ' '.join(item[1:])
|
||
|
elif len(item) == 1:
|
||
|
wanted_config[ item[0].strip() ] = ''
|
||
|
|
||
|
for key in wanted_config:
|
||
|
value = wanted_config[key]
|
||
|
if isinstance(value, bool):
|
||
|
if value:
|
||
|
wanted_config[key] = 'yes'
|
||
|
else:
|
||
|
wanted_config[key] = 'no'
|
||
|
|
||
|
current_config = get_selections(module, params["pkg"])
|
||
|
|
||
|
already_configured = 1
|
||
|
for answer in wanted_config:
|
||
|
if not answer in current_config or current_config[answer] != wanted_config[answer]:
|
||
|
already_configured = 0
|
||
|
|
||
|
if already_configured:
|
||
|
module.exit_json(changed=False, msg="Already configured")
|
||
|
else:
|
||
|
rc, msg = dpkg_reconfigure(module, pkg, wanted_config)
|
||
|
if not rc:
|
||
|
module.fail_json(msg=msg)
|
||
|
|
||
|
params['changed'] = True
|
||
|
params['msg'] = msg
|
||
|
return params
|
||
|
|
||
|
|
||
|
def main():
|
||
|
|
||
|
module = AnsibleModule(
|
||
|
argument_spec = dict(
|
||
|
pkg = dict(required=True),
|
||
|
answers = dict(required=True),
|
||
|
)
|
||
|
)
|
||
|
|
||
|
results = enforce_state(module, module.params)
|
||
|
module.exit_json(**results)
|
||
|
|
||
|
# this is magic, see lib/ansible/module_common.py
|
||
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||
|
main()
|