ini_file 5.85 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2012, Jan-Piet Mens <jpmens () gmail.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: 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:
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
  dest:
    description:
      - Path to the INI-style file; this file is created if required
    required: true
    default: null
  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
48
    default: null
49 50 51 52
  value:
    description:
     - the string value to be associated with an I(option). May be omitted when removing an I(option).
    required: false
53
    default: null
54 55 56 57 58 59 60 61 62 63 64
  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
65
examples:
66
   - code: "ini_file: dest=/etc/conf section=drinks option=fav value=lemonade mode=0600 backup=yes"
67 68
     description: Ensure C(fav=lemonade) is in section C([drinks]) in said file
   - code: |
69 70 71 72
           ini_file: dest=/etc/anotherconf
                     section=drinks
                     option=temperature
                     value=cold
73
                     backup=yes
74 75 76
notes:
   - While it is possible to add an I(option) without specifying a I(value), this makes
     no sense.
77 78 79 80
   - A section named C(default) cannot be added by the module, but if it exists, individual
     options within the section can be updated. (This is a limitation of Python's I(ConfigParser).)
     Either use M(template) to create a base INI file with a C([default]) section, or use
     M(lineinfile) to add the missing line.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
requirements: [ ConfigParser ]
author: Jan-Piet Mens
'''


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:
119 120 121
            if section.upper() == 'DEFAULT':
                module.fail_json(msg="[DEFAULT] is an illegal section name")

122 123 124 125 126 127 128 129 130
            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
131 132 133
            except ConfigParser.NoSectionError:
                cp.set(section, option, value)
                changed = True
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
            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(
        argument_spec = dict(
            dest = dict(required=True),
            section = dict(required=True),
            option = dict(required=False),
            value = dict(required=False),
161
            backup = dict(default='no', type='bool'),
162
            state = dict(default='present', choices=['present', 'absent'])
163 164
        ),
        add_file_common_args = True
165 166 167 168 169 170 171 172 173
    )

    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']
174
    backup = module.params['backup']
175 176 177

    changed = do_ini(module, dest, section, option, value, state, backup)

178 179
    file_args = module.load_file_common_arguments(module.params)
    changed = module.set_file_attributes_if_different(file_args, changed)
180 181

    # Mission complete
182
    module.exit_json(dest=dest, changed=changed, msg="OK")
183 184 185 186

# this is magic, see lib/ansible/module_common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()