assemble 4.09 KB
Newer Older
Stephen Fromm committed
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
Stephen Fromm committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

# (c) 2012, Stephen Fromm <sfromm@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/>.

import os
import os.path
import shutil
import tempfile
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
DOCUMENTATION = '''
---
module: assemble
short_description: Assembles a configuration file from fragments
description:
     - Assembles a configuration file from fragments. Often a particular
       program will take a single configuration file and does not support a
       C(conf.d) style structure where it is easy to build up the configuration
       from multiple sources. Assemble will take a directory of files that have
       already been transferred to the system, and concatenate them together to
       produce a destination file. Files are assembled in string sorting order.
       Puppet calls this idea I(fragments).
version_added: "0.5"
options:
  src:
    description:
      - An already existing directory full of source files.
    required: true
    default: null
    aliases: []
  dest:
    description:
      - A file to create using the concatenation of all of the source files.
    required: true
    default: null
  backup:
    description:
53
      - Create a backup file (if C(yes)), including the timestamp information so
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
        you can get the original file back if you somehow clobbered it
        incorrectly.
    required: false
    choices: [ "yes", "no" ]
    default: "no"
  others:
    description:
      - all arguments accepted by the M(file) module also work here
    required: false
examples:
   - code: assemble src=/etc/someapp/fragments dest=/etc/someapp/someapp.conf
     description: "Example from Ansible Playbooks"
author: Stephen Fromm
'''

Stephen Fromm committed
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
# ===========================================
# Support methods

def assemble_from_fragments(path):
    ''' assemble a file from a directory of fragments '''
    assembled = []
    for f in sorted(os.listdir(path)):
        fragment = "%s/%s" % (path, f)
        if os.path.isfile(fragment):
            assembled.append(file(fragment).read())
    return "".join(assembled)

def write_temp_file(data):
    fd, path = tempfile.mkstemp()
    os.write(fd, data)
    os.close(fd)
    return path

87 88 89 90
# ==============================================================
# main

def main():
91

92
    module = AnsibleModule(
93 94
        # not checking because of daisy chain to file module
        check_invalid_arguments = False,
95 96 97
        argument_spec = dict(
            src = dict(required=True),
            dest = dict(required=True),
98
            backup=dict(default=False, choices=BOOLEANS),
99 100
        )
    )
101

102 103 104 105 106
    changed=False
    pathmd5 = None
    destmd5 = None
    src = os.path.expanduser(module.params['src'])
    dest = os.path.expanduser(module.params['dest'])
107
    backup = module.boolean(module.params.get('backup', False))
108

109
    if not os.path.exists(src):
110
        module.fail_json(msg="Source (%s) does not exist" % src)
111

112
    if not os.path.isdir(src):
113
        module.fail_json(msg="Source (%s) is not a directory" % src)
114

115 116
    path = write_temp_file(assemble_from_fragments(src))
    pathmd5 = module.md5(path)
117

118 119
    if os.path.exists(dest):
        destmd5 = module.md5(dest)
120

121
    if pathmd5 != destmd5:
122
        if backup and destmd5 is not None:
123
            module.backup_local(dest)
124 125
        shutil.copy(path, dest)
        changed = True
126

127 128

    # Mission complete
129
    module.exit_json(src=src, dest=dest, md5sum=destmd5,
130 131 132 133 134 135 136
        changed=changed, msg="OK",
        daisychain="file", daisychain_args=module.params)

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

main()