175 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/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()
 |