From c2daa770892b27a0ffbe666e8db84dcdf99e6a00 Mon Sep 17 00:00:00 2001 From: Jan-Piet Mens Date: Wed, 26 Sep 2012 13:18:20 +0200 Subject: [PATCH] New module: manipulate INI-style settings split off examples from DOCUMENTATION into own array as per #1098 --- library/ini_file | 185 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100755 library/ini_file diff --git a/library/ini_file b/library/ini_file new file mode 100755 index 0000000000..99fe9ee5a6 --- /dev/null +++ b/library/ini_file @@ -0,0 +1,185 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2012, Jan-Piet Mens +# +# 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 . +# + +DOCUMENTATION = ''' +--- +module: ini_file +short_description: Tweak settings in INI files +description: + - Manage (add, remove, change) individual settings in an INI-style file without having + to manage the file as a whole with, say, M(template) or M(assemble). Adds missing + sections if they don't exist. +version_added: "0.9" +options: + - dest: + description: + - Path to the INI-style file; this file is created if required + required: true + default: null + aliases: [] + - section: + description: + - Section name in INI file. This is added if C(state=present) automatically when + a single value is being set. + required: true + default: null + - option: + description: + - if set (required for changing a I(value)), this is the name of the option. + - May be omitted if adding/removing a whole I(section). + required: false + default: [] + - value: + description: + - the string value to be associated with an I(option). May be omitted when + removing an I(option). + required: false + default: [] + - backup: + description: + - Create a backup file including the timestamp information so you can get + the original file back if you somehow clobbered it incorrectly. + required: false + default: no + choices: [ "yes", "no" ] + - others: + description: + - all arguments accepted by the M(file) module also work here + required: false +notes: + - While it is possible to add an I(option) without specifying a I(value), this makes + no sense. +requirements: [ ConfigParser ] +author: Jan-Piet Mens +''' + +EXAMPLES = [ +""" +- code: ini_file dest=/etc/conf section=drinks option=fav value=lemonade mode=0600 backup=true + description: Ensure C(fav=lemonade) is in section C([drinks]) in said file +""", +""" ini_file dest=/etc/anotherconf + section=drinks + option=temperature + value=cold + backup=true +""" +] + +import ConfigParser + +# ============================================================== +# do_ini + +def do_ini(module, filename, section=None, option=None, value=None, state='present', backup=False): + + changed = False + cp = ConfigParser.ConfigParser() + + try: + f = open(filename) + cp.readfp(f) + except IOError: + pass + + + if state == 'absent': + if option is None and value is None: + if cp.has_section(section): + cp.remove_section(section) + changed = True + else: + if option is not None: + try: + if cp.get(section, option): + cp.remove_option(section, option) + changed = True + except: + pass + + if state == 'present': + if cp.has_section(section) == False: + cp.add_section(section) + changed = True + + if option is not None and value is not None: + try: + oldvalue = cp.get(section, option) + if str(value) != str(oldvalue): + cp.set(section, option, value) + changed = True + except ConfigParser.NoOptionError: + cp.set(section, option, value) + changed = True + + if changed: + if backup: + module.backup_local(filename) + + try: + f = open(filename, 'w') + cp.write(f) + except: + module.fail_json(msg="Can't creat %s" % filename) + + return changed + +# ============================================================== +# main + +def main(): + + module = AnsibleModule( + # not checking because of daisy chain to file module + check_invalid_arguments = False, + argument_spec = dict( + dest = dict(required=True), + section = dict(required=True), + option = dict(required=False), + value = dict(required=False), + backup = dict(default='no', choices=BOOLEANS), + state = dict(default='present', choices=['present', 'absent']) + ) + ) + + info = dict() + + dest = os.path.expanduser(module.params['dest']) + section = module.params['section'] + option = module.params['option'] + value = module.params['value'] + state = module.params['state'] + backup = module.boolean(module.params['backup']) + + changed = do_ini(module, dest, section, option, value, state, backup) + + info['daisychain_args'] = module.params + info['daisychain_args']['state'] = 'file' + info['daisychain_args']['dest'] = dest + + # Mission complete + module.exit_json(dest=dest, + changed=changed, msg="OK", + daisychain="file", daisychain_args=info.get('daisychain_args','')) + +# this is magic, see lib/ansible/module_common.py +#<> +main()