summaryrefslogtreecommitdiff
path: root/files
diff options
context:
space:
mode:
authorMichael DeHaan <michael.dehaan@gmail.com>2014-09-26 09:23:50 -0400
committerMichael DeHaan <michael.dehaan@gmail.com>2014-09-26 09:23:50 -0400
commit73123b69fa5c15babaf28b2e5980b946ead1ace5 (patch)
treec757a913f95f26d08ebca9e2fbe586ccb1e45e7e /files
parentb2b5cc032caf22ece54852dc023b888baf109c8b (diff)
downloadansible-modules-extras-73123b69fa5c15babaf28b2e5980b946ead1ace5.tar.gz
Move modules into subdirectory.
Diffstat (limited to 'files')
-rw-r--r--files/acl295
-rw-r--r--files/assemble200
-rw-r--r--files/copy254
-rw-r--r--files/fetch67
-rw-r--r--files/file358
-rw-r--r--files/ini_file207
-rw-r--r--files/lineinfile400
-rw-r--r--files/replace162
-rw-r--r--files/stat152
-rw-r--r--files/synchronize345
-rw-r--r--files/template66
-rw-r--r--files/unarchive250
-rw-r--r--files/xattr206
13 files changed, 0 insertions, 2962 deletions
diff --git a/files/acl b/files/acl
deleted file mode 100644
index 30c533e0..00000000
--- a/files/acl
+++ /dev/null
@@ -1,295 +0,0 @@
-#!/usr/bin/python
-# 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: acl
-version_added: "1.4"
-short_description: Sets and retrieves file ACL information.
-description:
- - Sets and retrieves file ACL information.
-options:
- name:
- required: true
- default: null
- description:
- - The full path of the file or object.
- aliases: ['path']
-
- state:
- required: false
- default: query
- choices: [ 'query', 'present', 'absent' ]
- description:
- - defines whether the ACL should be present or not. The C(query) state gets the current acl without changing it, for use in 'register' operations.
-
- follow:
- required: false
- default: yes
- choices: [ 'yes', 'no' ]
- description:
- - whether to follow symlinks on the path if a symlink is encountered.
-
- default:
- version_added: "1.5"
- required: false
- default: no
- choices: [ 'yes', 'no' ]
- description:
- - if the target is a directory, setting this to yes will make it the default acl for entities created inside the directory. It causes an error if name is a file.
-
- entity:
- version_added: "1.5"
- required: false
- description:
- - actual user or group that the ACL applies to when matching entity types user or group are selected.
-
- etype:
- version_added: "1.5"
- required: false
- default: null
- choices: [ 'user', 'group', 'mask', 'other' ]
- description:
- - the entity type of the ACL to apply, see setfacl documentation for more info.
-
-
- permissions:
- version_added: "1.5"
- required: false
- default: null
- description:
- - Permissions to apply/remove can be any combination of r, w and x (read, write and execute respectively)
-
- entry:
- required: false
- default: null
- description:
- - DEPRECATED. The acl to set or remove. This must always be quoted in the form of '<etype>:<qualifier>:<perms>'. The qualifier may be empty for some types, but the type and perms are always requried. '-' can be used as placeholder when you do not care about permissions. This is now superseded by entity, type and permissions fields.
-
-author: Brian Coca
-notes:
- - The "acl" module requires that acls are enabled on the target filesystem and that the setfacl and getfacl binaries are installed.
-'''
-
-EXAMPLES = '''
-# Grant user Joe read access to a file
-- acl: name=/etc/foo.conf entity=joe etype=user permissions="r" state=present
-
-# Removes the acl for Joe on a specific file
-- acl: name=/etc/foo.conf entity=joe etype=user state=absent
-
-# Sets default acl for joe on foo.d
-- acl: name=/etc/foo.d entity=joe etype=user permissions=rw default=yes state=present
-
-# Same as previous but using entry shorthand
-- acl: name=/etc/foo.d entry="default:user:joe:rw-" state=present
-
-# Obtain the acl for a specific file
-- acl: name=/etc/foo.conf
- register: acl_info
-'''
-
-def normalize_permissions(p):
- perms = ['-','-','-']
- for char in p:
- if char == 'r':
- perms[0] = 'r'
- if char == 'w':
- perms[1] = 'w'
- if char == 'x':
- perms[2] = 'x'
- return ''.join(perms)
-
-def split_entry(entry):
- ''' splits entry and ensures normalized return'''
-
- a = entry.split(':')
- a.reverse()
- if len(a) == 3:
- a.append(False)
- try:
- p,e,t,d = a
- except ValueError, e:
- print "wtf?? %s => %s" % (entry,a)
- raise e
-
- if d:
- d = True
-
- if t.startswith("u"):
- t = "user"
- elif t.startswith("g"):
- t = "group"
- elif t.startswith("m"):
- t = "mask"
- elif t.startswith("o"):
- t = "other"
- else:
- t = None
-
- p = normalize_permissions(p)
-
- return [d,t,e,p]
-
-def get_acls(module,path,follow):
-
- cmd = [ module.get_bin_path('getfacl', True) ]
- if not follow:
- cmd.append('-h')
- # prevents absolute path warnings and removes headers
- cmd.append('--omit-header')
- cmd.append('--absolute-names')
- cmd.append(path)
-
- return _run_acl(module,cmd)
-
-def set_acl(module,path,entry,follow,default):
-
- cmd = [ module.get_bin_path('setfacl', True) ]
- if not follow:
- cmd.append('-h')
- if default:
- cmd.append('-d')
- cmd.append('-m "%s"' % entry)
- cmd.append(path)
-
- return _run_acl(module,cmd)
-
-def rm_acl(module,path,entry,follow,default):
-
- cmd = [ module.get_bin_path('setfacl', True) ]
- if not follow:
- cmd.append('-h')
- if default:
- cmd.append('-k')
- entry = entry[0:entry.rfind(':')]
- cmd.append('-x "%s"' % entry)
- cmd.append(path)
-
- return _run_acl(module,cmd,False)
-
-def _run_acl(module,cmd,check_rc=True):
-
- try:
- (rc, out, err) = module.run_command(' '.join(cmd), check_rc=check_rc)
- except Exception, e:
- module.fail_json(msg=e.strerror)
-
- # trim last line as it is always empty
- ret = out.splitlines()
- return ret[0:len(ret)-1]
-
-def main():
- module = AnsibleModule(
- argument_spec = dict(
- name = dict(required=True,aliases=['path'], type='str'),
- entry = dict(required=False, etype='str'),
- entity = dict(required=False, type='str', default=''),
- etype = dict(required=False, choices=['other', 'user', 'group', 'mask'], type='str'),
- permissions = dict(required=False, type='str'),
- state = dict(required=False, default='query', choices=[ 'query', 'present', 'absent' ], type='str'),
- follow = dict(required=False, type='bool', default=True),
- default= dict(required=False, type='bool', default=False),
- ),
- supports_check_mode=True,
- )
-
- path = os.path.expanduser(module.params.get('name'))
- entry = module.params.get('entry')
- entity = module.params.get('entity')
- etype = module.params.get('etype')
- permissions = module.params.get('permissions')
- state = module.params.get('state')
- follow = module.params.get('follow')
- default = module.params.get('default')
-
- if permissions:
- permissions = normalize_permissions(permissions)
-
- if not os.path.exists(path):
- module.fail_json(msg="path not found or not accessible!")
-
- if state in ['present','absent']:
- if not entry and not etype:
- module.fail_json(msg="%s requires either etype and permissions or just entry be set" % state)
-
- if entry:
- if etype or entity or permissions:
- module.fail_json(msg="entry and another incompatible field (entity, etype or permissions) are also set")
- if entry.count(":") not in [2,3]:
- module.fail_json(msg="Invalid entry: '%s', it requires 3 or 4 sections divided by ':'" % entry)
-
- default, etype, entity, permissions = split_entry(entry)
-
- changed=False
- msg = ""
- currentacls = get_acls(module,path,follow)
-
- if (state == 'present'):
- matched = False
- for oldentry in currentacls:
- if oldentry.count(":") == 0:
- continue
- old_default, old_type, old_entity, old_permissions = split_entry(oldentry)
- if old_default == default:
- if old_type == etype:
- if etype in ['user', 'group']:
- if old_entity == entity:
- matched = True
- if not old_permissions == permissions:
- changed = True
- break
- else:
- matched = True
- if not old_permissions == permissions:
- changed = True
- break
- if not matched:
- changed=True
-
- if changed and not module.check_mode:
- set_acl(module,path,':'.join([etype, str(entity), permissions]),follow,default)
- msg="%s is present" % ':'.join([etype, str(entity), permissions])
-
- elif state == 'absent':
- for oldentry in currentacls:
- if oldentry.count(":") == 0:
- continue
- old_default, old_type, old_entity, old_permissions = split_entry(oldentry)
- if old_default == default:
- if old_type == etype:
- if etype in ['user', 'group']:
- if old_entity == entity:
- changed=True
- break
- else:
- changed=True
- break
- if changed and not module.check_mode:
- rm_acl(module,path,':'.join([etype, entity, '---']),follow,default)
- msg="%s is absent" % ':'.join([etype, entity, '---'])
- else:
- msg="current acl"
-
- if changed:
- currentacls = get_acls(module,path,follow)
-
- module.exit_json(changed=changed, msg=msg, acl=currentacls)
-
-# import module snippets
-from ansible.module_utils.basic import *
-
-main()
diff --git a/files/assemble b/files/assemble
deleted file mode 100644
index a16431b9..00000000
--- a/files/assemble
+++ /dev/null
@@ -1,200 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (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
-import re
-
-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. M(assemble) will take a directory of files that can be
- local or 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:
- - Create a backup file (if C(yes)), including the timestamp information so
- you can get the original file back if you somehow clobbered it
- incorrectly.
- required: false
- choices: [ "yes", "no" ]
- default: "no"
- delimiter:
- description:
- - A delimiter to separate the file contents.
- version_added: "1.4"
- required: false
- default: null
- remote_src:
- description:
- - If False, it will search for src at originating/master machine, if True it will
- go to the remote/target machine for the src. Default is True.
- choices: [ "True", "False" ]
- required: false
- default: "True"
- version_added: "1.4"
- regexp:
- description:
- - Assemble files only if C(regex) matches the filename. If not set,
- all files are assembled. All "\\" (backslash) must be escaped as
- "\\\\" to comply yaml syntax. Uses Python regular expressions; see
- U(http://docs.python.org/2/library/re.html).
- required: false
- default: null
-author: Stephen Fromm
-extends_documentation_fragment: files
-'''
-
-EXAMPLES = '''
-# Example from Ansible Playbooks
-- assemble: src=/etc/someapp/fragments dest=/etc/someapp/someapp.conf
-
-# When a delimiter is specified, it will be inserted in between each fragment
-- assemble: src=/etc/someapp/fragments dest=/etc/someapp/someapp.conf delimiter='### START FRAGMENT ###'
-'''
-
-# ===========================================
-# Support method
-
-def assemble_from_fragments(src_path, delimiter=None, compiled_regexp=None):
- ''' assemble a file from a directory of fragments '''
- tmpfd, temp_path = tempfile.mkstemp()
- tmp = os.fdopen(tmpfd,'w')
- delimit_me = False
- add_newline = False
-
- for f in sorted(os.listdir(src_path)):
- if compiled_regexp and not compiled_regexp.search(f):
- continue
- fragment = "%s/%s" % (src_path, f)
- if not os.path.isfile(fragment):
- continue
- fragment_content = file(fragment).read()
-
- # always put a newline between fragments if the previous fragment didn't end with a newline.
- if add_newline:
- tmp.write('\n')
-
- # delimiters should only appear between fragments
- if delimit_me:
- if delimiter:
- # un-escape anything like newlines
- delimiter = delimiter.decode('unicode-escape')
- tmp.write(delimiter)
- # always make sure there's a newline after the
- # delimiter, so lines don't run together
- if delimiter[-1] != '\n':
- tmp.write('\n')
-
- tmp.write(fragment_content)
- delimit_me = True
- if fragment_content.endswith('\n'):
- add_newline = False
- else:
- add_newline = True
-
- tmp.close()
- return temp_path
-
-# ==============================================================
-# main
-
-def main():
-
- module = AnsibleModule(
- # not checking because of daisy chain to file module
- argument_spec = dict(
- src = dict(required=True),
- delimiter = dict(required=False),
- dest = dict(required=True),
- backup=dict(default=False, type='bool'),
- remote_src=dict(default=False, type='bool'),
- regexp = dict(required=False),
- ),
- add_file_common_args=True
- )
-
- changed = False
- pathmd5 = None
- destmd5 = None
- src = os.path.expanduser(module.params['src'])
- dest = os.path.expanduser(module.params['dest'])
- backup = module.params['backup']
- delimiter = module.params['delimiter']
- regexp = module.params['regexp']
- compiled_regexp = None
-
- if not os.path.exists(src):
- module.fail_json(msg="Source (%s) does not exist" % src)
-
- if not os.path.isdir(src):
- module.fail_json(msg="Source (%s) is not a directory" % src)
-
- if regexp != None:
- try:
- compiled_regexp = re.compile(regexp)
- except re.error, e:
- module.fail_json(msg="Invalid Regexp (%s) in \"%s\"" % (e, regexp))
-
- path = assemble_from_fragments(src, delimiter, compiled_regexp)
- pathmd5 = module.md5(path)
-
- if os.path.exists(dest):
- destmd5 = module.md5(dest)
-
- if pathmd5 != destmd5:
- if backup and destmd5 is not None:
- module.backup_local(dest)
- shutil.copy(path, dest)
- changed = True
-
- os.remove(path)
-
- file_args = module.load_file_common_arguments(module.params)
- changed = module.set_fs_attributes_if_different(file_args, changed)
- # Mission complete
- module.exit_json(src=src, dest=dest, md5sum=pathmd5, changed=changed, msg="OK")
-
-# import module snippets
-from ansible.module_utils.basic import *
-
-main()
-
diff --git a/files/copy b/files/copy
deleted file mode 100644
index eff46dae..00000000
--- a/files/copy
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2012, Michael DeHaan <michael.dehaan@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 time
-
-DOCUMENTATION = '''
----
-module: copy
-version_added: "historical"
-short_description: Copies files to remote locations.
-description:
- - The M(copy) module copies a file on the local box to remote locations.
-options:
- src:
- description:
- - Local path to a file to copy to the remote server; can be absolute or relative.
- If path is a directory, it is copied recursively. In this case, if path ends
- with "/", only inside contents of that directory are copied to destination.
- Otherwise, if it does not end with "/", the directory itself with all contents
- is copied. This behavior is similar to Rsync.
- required: false
- default: null
- aliases: []
- content:
- version_added: "1.1"
- description:
- - When used instead of 'src', sets the contents of a file directly to the specified value.
- required: false
- default: null
- dest:
- description:
- - Remote absolute path where the file should be copied to. If src is a directory,
- this must be a directory too.
- required: true
- default: null
- backup:
- description:
- - Create a backup file including the timestamp information so you can get
- the original file back if you somehow clobbered it incorrectly.
- version_added: "0.7"
- required: false
- choices: [ "yes", "no" ]
- default: "no"
- force:
- description:
- - the default is C(yes), which will replace the remote file when contents
- are different than the source. If C(no), the file will only be transferred
- if the destination does not exist.
- version_added: "1.1"
- required: false
- choices: [ "yes", "no" ]
- default: "yes"
- aliases: [ "thirsty" ]
- validate:
- description:
- - The validation command to run before copying into place. The path to the file to
- validate is passed in via '%s' which must be present as in the visudo example below.
- The command is passed securely so shell features like expansion and pipes won't work.
- required: false
- default: ""
- version_added: "1.2"
- directory_mode:
- description:
- - When doing a recursive copy set the mode for the directories. If this is not set we will use the system
- defaults. The mode is only set on directories which are newly created, and will not affect those that
- already existed.
- required: false
- version_added: "1.5"
-extends_documentation_fragment: files
-author: Michael DeHaan
-notes:
- - The "copy" module recursively copy facility does not scale to lots (>hundreds) of files.
- For alternative, see synchronize module, which is a wrapper around rsync.
-'''
-
-EXAMPLES = '''
-# Example from Ansible Playbooks
-- copy: src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode=0644
-
-# The same example as above, but using a symbolic mode equivalent to 0644
-- copy: src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode="u=rw,g=r,o=r"
-
-# Another symbolic mode example, adding some permissions and removing others
-- copy: src=/srv/myfiles/foo.conf dest=/etc/foo.conf owner=foo group=foo mode="u+rw,g-wx,o-rwx"
-
-# Copy a new "ntp.conf file into place, backing up the original if it differs from the copied version
-- copy: src=/mine/ntp.conf dest=/etc/ntp.conf owner=root group=root mode=644 backup=yes
-
-# Copy a new "sudoers" file into place, after passing validation with visudo
-- copy: src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'
-'''
-
-
-def split_pre_existing_dir(dirname):
- '''
- Return the first pre-existing directory and a list of the new directories that will be created.
- '''
-
- head, tail = os.path.split(dirname)
- if not os.path.exists(head):
- (pre_existing_dir, new_directory_list) = split_pre_existing_dir(head)
- else:
- return (head, [ tail ])
- new_directory_list.append(tail)
- return (pre_existing_dir, new_directory_list)
-
-
-def adjust_recursive_directory_permissions(pre_existing_dir, new_directory_list, module, directory_args, changed):
- '''
- Walk the new directories list and make sure that permissions are as we would expect
- '''
-
- if len(new_directory_list) > 0:
- working_dir = os.path.join(pre_existing_dir, new_directory_list.pop(0))
- directory_args['path'] = working_dir
- changed = module.set_fs_attributes_if_different(directory_args, changed)
- changed = adjust_recursive_directory_permissions(working_dir, new_directory_list, module, directory_args, changed)
- return changed
-
-
-def main():
-
- module = AnsibleModule(
- # not checking because of daisy chain to file module
- argument_spec = dict(
- src = dict(required=False),
- original_basename = dict(required=False), # used to handle 'dest is a directory' via template, a slight hack
- content = dict(required=False, no_log=True),
- dest = dict(required=True),
- backup = dict(default=False, type='bool'),
- force = dict(default=True, aliases=['thirsty'], type='bool'),
- validate = dict(required=False, type='str'),
- directory_mode = dict(required=False)
- ),
- add_file_common_args=True,
- supports_check_mode=True,
- )
-
- src = os.path.expanduser(module.params['src'])
- dest = os.path.expanduser(module.params['dest'])
- backup = module.params['backup']
- force = module.params['force']
- original_basename = module.params.get('original_basename',None)
- validate = module.params.get('validate',None)
- follow = module.params['follow']
-
- if not os.path.exists(src):
- module.fail_json(msg="Source %s failed to transfer" % (src))
- if not os.access(src, os.R_OK):
- module.fail_json(msg="Source %s not readable" % (src))
-
- md5sum_src = module.md5(src)
- md5sum_dest = None
-
- changed = False
-
- # Special handling for recursive copy - create intermediate dirs
- if original_basename and dest.endswith("/"):
- dest = os.path.join(dest, original_basename)
- dirname = os.path.dirname(dest)
- if not os.path.exists(dirname):
- (pre_existing_dir, new_directory_list) = split_pre_existing_dir(dirname)
- os.makedirs(dirname)
- directory_args = module.load_file_common_arguments(module.params)
- directory_mode = module.params["directory_mode"]
- if directory_mode is not None:
- directory_args['mode'] = directory_mode
- else:
- directory_args['mode'] = None
- adjust_recursive_directory_permissions(pre_existing_dir, new_directory_list, module, directory_args, changed)
-
- if os.path.exists(dest):
- if os.path.islink(dest) and follow:
- dest = os.path.realpath(dest)
- if not force:
- module.exit_json(msg="file already exists", src=src, dest=dest, changed=False)
- if (os.path.isdir(dest)):
- basename = os.path.basename(src)
- if original_basename:
- basename = original_basename
- dest = os.path.join(dest, basename)
- if os.access(dest, os.R_OK):
- md5sum_dest = module.md5(dest)
- else:
- if not os.path.exists(os.path.dirname(dest)):
- try:
- # os.path.exists() can return false in some
- # circumstances where the directory does not have
- # the execute bit for the current user set, in
- # which case the stat() call will raise an OSError
- os.stat(os.path.dirname(dest))
- except OSError, e:
- if "permission denied" in str(e).lower():
- module.fail_json(msg="Destination directory %s is not accessible" % (os.path.dirname(dest)))
- module.fail_json(msg="Destination directory %s does not exist" % (os.path.dirname(dest)))
- if not os.access(os.path.dirname(dest), os.W_OK):
- module.fail_json(msg="Destination %s not writable" % (os.path.dirname(dest)))
-
- backup_file = None
- if md5sum_src != md5sum_dest or os.path.islink(dest):
- try:
- if backup:
- if os.path.exists(dest):
- backup_file = module.backup_local(dest)
- # allow for conversion from symlink.
- if os.path.islink(dest):
- os.unlink(dest)
- open(dest, 'w').close()
- if validate:
- if "%s" not in validate:
- module.fail_json(msg="validate must contain %%s: %s" % (validate))
- (rc,out,err) = module.run_command(validate % src)
- if rc != 0:
- module.fail_json(msg="failed to validate: rc:%s error:%s" % (rc,err))
- module.atomic_move(src, dest)
- except IOError:
- module.fail_json(msg="failed to copy: %s to %s" % (src, dest))
- changed = True
- else:
- changed = False
-
- res_args = dict(
- dest = dest, src = src, md5sum = md5sum_src, changed = changed
- )
- if backup_file:
- res_args['backup_file'] = backup_file
-
- module.params['dest'] = dest
- file_args = module.load_file_common_arguments(module.params)
- res_args['changed'] = module.set_fs_attributes_if_different(file_args, res_args['changed'])
-
- module.exit_json(**res_args)
-
-# import module snippets
-from ansible.module_utils.basic import *
-main()
diff --git a/files/fetch b/files/fetch
deleted file mode 100644
index 5b47d87a..00000000
--- a/files/fetch
+++ /dev/null
@@ -1,67 +0,0 @@
-# this is a virtual module that is entirely implemented server side
-
-DOCUMENTATION = '''
----
-module: fetch
-short_description: Fetches a file from remote nodes
-description:
- - This module works like M(copy), but in reverse. It is used for fetching
- files from remote machines and storing them locally in a file tree,
- organized by hostname. Note that this module is written to transfer
- log files that might not be present, so a missing remote file won't
- be an error unless fail_on_missing is set to 'yes'.
-version_added: "0.2"
-options:
- src:
- description:
- - The file on the remote system to fetch. This I(must) be a file, not a
- directory. Recursive fetching may be supported in a later release.
- required: true
- default: null
- aliases: []
- dest:
- description:
- - A directory to save the file into. For example, if the I(dest)
- directory is C(/backup) a I(src) file named C(/etc/profile) on host
- C(host.example.com), would be saved into
- C(/backup/host.example.com/etc/profile)
- required: true
- default: null
- fail_on_missing:
- version_added: "1.1"
- description:
- - Makes it fails when the source file is missing.
- required: false
- choices: [ "yes", "no" ]
- default: "no"
- validate_md5:
- version_added: "1.4"
- description:
- - Verify that the source and destination md5sums match after the files are fetched.
- required: false
- choices: [ "yes", "no" ]
- default: "yes"
- flat:
- version_added: "1.2"
- description:
- Allows you to override the default behavior of prepending hostname/path/to/file to
- the destination. If dest ends with '/', it will use the basename of the source
- file, similar to the copy module. Obviously this is only handy if the filenames
- are unique.
-requirements: []
-author: Michael DeHaan
-'''
-
-EXAMPLES = '''
-# Store file into /tmp/fetched/host.example.com/tmp/somefile
-- fetch: src=/tmp/somefile dest=/tmp/fetched
-
-# Specifying a path directly
-- fetch: src=/tmp/somefile dest=/tmp/prefix-{{ ansible_hostname }} flat=yes
-
-# Specifying a destination path
-- fetch: src=/tmp/uniquefile dest=/tmp/special/ flat=yes
-
-# Storing in a path relative to the playbook
-- fetch: src=/tmp/uniquefile dest=special/prefix-{{ ansible_hostname }} flat=yes
-'''
diff --git a/files/file b/files/file
deleted file mode 100644
index ff9feb41..00000000
--- a/files/file
+++ /dev/null
@@ -1,358 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2012, Michael DeHaan <michael.dehaan@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 shutil
-import stat
-import grp
-import pwd
-try:
- import selinux
- HAVE_SELINUX=True
-except ImportError:
- HAVE_SELINUX=False
-
-DOCUMENTATION = '''
----
-module: file
-version_added: "historical"
-short_description: Sets attributes of files
-extends_documentation_fragment: files
-description:
- - Sets attributes of files, symlinks, and directories, or removes
- files/symlinks/directories. Many other modules support the same options as
- the M(file) module - including M(copy), M(template), and M(assemble).
-notes:
- - See also M(copy), M(template), M(assemble)
-requirements: [ ]
-author: Michael DeHaan
-options:
- path:
- description:
- - 'path to the file being managed. Aliases: I(dest), I(name)'
- required: true
- default: []
- aliases: ['dest', 'name']
- state:
- description:
- - If C(directory), all immediate subdirectories will be created if they
- do not exist, since 1.7 they will be created with the supplied permissions.
- If C(file), the file will NOT be created if it does not exist, see the M(copy)
- or M(template) module if you want that behavior. If C(link), the symbolic
- link will be created or changed. Use C(hard) for hardlinks. If C(absent),
- directories will be recursively deleted, and files or symlinks will be unlinked.
- If C(touch) (new in 1.4), an empty file will be created if the c(path) does not
- exist, while an existing file or directory will receive updated file access and
- modification times (similar to the way `touch` works from the command line).
- required: false
- default: file
- choices: [ file, link, directory, hard, touch, absent ]
- src:
- required: false
- default: null
- choices: []
- description:
- - path of the file to link to (applies only to C(state=link)). Will accept absolute,
- relative and nonexisting paths. Relative paths are not expanded.
- recurse:
- required: false
- default: "no"
- choices: [ "yes", "no" ]
- version_added: "1.1"
- description:
- - recursively set the specified file attributes (applies only to state=directory)
- force:
- required: false
- default: "no"
- choices: [ "yes", "no" ]
- description:
- - 'force the creation of the symlinks in two cases: the source file does
- not exist (but will appear later); the destination exists and is a file (so, we need to unlink the
- "path" file and create symlink to the "src" file in place of it).'
-'''
-
-EXAMPLES = '''
-- file: path=/etc/foo.conf owner=foo group=foo mode=0644
-- file: src=/file/to/link/to dest=/path/to/symlink owner=foo group=foo state=link
-- file: src=/tmp/{{ item.path }} dest={{ item.dest }} state=link
- with_items:
- - { path: 'x', dest: 'y' }
- - { path: 'z', dest: 'k' }
-
-# touch a file, using symbolic modes to set the permissions (equivalent to 0644)
-- file: path=/etc/foo.conf state=touch mode="u=rw,g=r,o=r"
-
-# touch the same file, but add/remove some permissions
-- file: path=/etc/foo.conf state=touch mode="u+rw,g-wx,o-rwx"
-
-'''
-
-def main():
-
- module = AnsibleModule(
- argument_spec = dict(
- state = dict(choices=['file','directory','link','hard','touch','absent'], default=None),
- path = dict(aliases=['dest', 'name'], required=True),
- original_basename = dict(required=False), # Internal use only, for recursive ops
- recurse = dict(default='no', type='bool'),
- force = dict(required=False,default=False,type='bool'),
- diff_peek = dict(default=None),
- validate = dict(required=False, default=None),
- src = dict(required=False, default=None),
- ),
- add_file_common_args=True,
- supports_check_mode=True
- )
-
- params = module.params
- state = params['state']
- force = params['force']
- diff_peek = params['diff_peek']
- src = params['src']
- follow = params['follow']
-
- # modify source as we later reload and pass, specially relevant when used by other modules.
- params['path'] = path = os.path.expanduser(params['path'])
-
- # short-circuit for diff_peek
- if diff_peek is not None:
- appears_binary = False
- try:
- f = open(path)
- b = f.read(8192)
- f.close()
- if "\x00" in b:
- appears_binary = True
- except:
- pass
- module.exit_json(path=path, changed=False, appears_binary=appears_binary)
-
- # Find out current state
- prev_state = 'absent'
- if os.path.lexists(path):
- if os.path.islink(path):
- prev_state = 'link'
- elif os.path.isdir(path):
- prev_state = 'directory'
- elif os.stat(path).st_nlink > 1:
- prev_state = 'hard'
- else:
- # could be many other things, but defaulting to file
- prev_state = 'file'
-
- # state should default to file, but since that creates many conflicts,
- # default to 'current' when it exists.
- if state is None:
- if prev_state != 'absent':
- state = prev_state
- else:
- state = 'file'
-
- # source is both the source of a symlink or an informational passing of the src for a template module
- # or copy module, even if this module never uses it, it is needed to key off some things
- if src is not None:
- src = os.path.expanduser(src)
-
- # original_basename is used by other modules that depend on file.
- if os.path.isdir(path) and state not in ["link", "absent"]:
- if params['original_basename']:
- basename = params['original_basename']
- else:
- basename = os.path.basename(src)
- params['path'] = path = os.path.join(path, basename)
- else:
- if state in ['link','hard']:
- if follow:
- # use the current target of the link as the source
- src = os.readlink(path)
- else:
- module.fail_json(msg='src and dest are required for creating links')
-
- # make sure the target path is a directory when we're doing a recursive operation
- recurse = params['recurse']
- if recurse and state != 'directory':
- module.fail_json(path=path, msg="recurse option requires state to be 'directory'")
-
- file_args = module.load_file_common_arguments(params)
- changed = False
-
- if state == 'absent':
- if state != prev_state:
- if not module.check_mode:
- if prev_state == 'directory':
- try:
- shutil.rmtree(path, ignore_errors=False)
- except Exception, e:
- module.fail_json(msg="rmtree failed: %s" % str(e))
- else:
- try:
- os.unlink(path)
- except Exception, e:
- module.fail_json(path=path, msg="unlinking failed: %s " % str(e))
- module.exit_json(path=path, changed=True)
- else:
- module.exit_json(path=path, changed=False)
-
- elif state == 'file':
- if state != prev_state:
- # file is not absent and any other state is a conflict
- module.fail_json(path=path, msg='file (%s) is %s, cannot continue' % (path, prev_state))
-
- changed = module.set_fs_attributes_if_different(file_args, changed)
- module.exit_json(path=path, changed=changed)
-
- elif state == 'directory':
- if prev_state == 'absent':
- if module.check_mode:
- module.exit_json(changed=True)
- changed = True
- curpath = ''
- # Split the path so we can apply filesystem attributes recursively
- # from the root (/) directory for absolute paths or the base path
- # of a relative path. We can then walk the appropriate directory
- # path to apply attributes.
- for dirname in path.strip('/').split('/'):
- curpath = '/'.join([curpath, dirname])
- # Remove leading slash if we're creating a relative path
- if not os.path.isabs(path):
- curpath = curpath.lstrip('/')
- if not os.path.exists(curpath):
- os.mkdir(curpath)
- tmp_file_args = file_args.copy()
- tmp_file_args['path']=curpath
- changed = module.set_fs_attributes_if_different(tmp_file_args, changed)
-
- changed = module.set_fs_attributes_if_different(file_args, changed)
-
- if recurse:
- for root,dirs,files in os.walk( file_args['path'] ):
- for fsobj in dirs + files:
- fsname=os.path.join(root, fsobj)
- tmp_file_args = file_args.copy()
- tmp_file_args['path']=fsname
- changed = module.set_fs_attributes_if_different(tmp_file_args, changed)
-
- module.exit_json(path=path, changed=changed)
-
- elif state in ['link','hard']:
-
- if os.path.isdir(path) and not os.path.islink(path):
- relpath = path
- else:
- relpath = os.path.dirname(path)
-
- absrc = os.path.join(relpath, src)
- if not os.path.exists(absrc) and not force:
- module.fail_json(path=path, src=src, msg='src file does not exist, use "force=yes" if you really want to create the link: %s' % absrc)
-
- if state == 'hard':
- if not os.path.isabs(src):
- module.fail_json(msg="absolute paths are required")
- elif prev_state == 'directory':
- if not force:
- module.fail_json(path=path, msg='refusing to convert between %s and %s for %s' % (prev_state, state, path))
- elif len(os.listdir(path)) > 0:
- # refuse to replace a directory that has files in it
- module.fail_json(path=path, msg='the directory %s is not empty, refusing to convert it' % path)
- elif prev_state in ['file', 'hard'] and not force:
- module.fail_json(path=path, msg='refusing to convert between %s and %s for %s' % (prev_state, state, path))
-
- if prev_state == 'absent':
- changed = True
- elif prev_state == 'link':
- old_src = os.readlink(path)
- if old_src != src:
- changed = True
- elif prev_state == 'hard':
- if not (state == 'hard' and os.stat(path).st_ino == os.stat(src).st_ino):
- changed = True
- if not force:
- module.fail_json(dest=path, src=src, msg='Cannot link, different hard link exists at destination')
- elif prev_state in ['file', 'directory']:
- changed = True
- if not force:
- module.fail_json(dest=path, src=src, msg='Cannot link, %s exists at destination' % prev_state)
- else:
- module.fail_json(dest=path, src=src, msg='unexpected position reached')
-
- if changed and not module.check_mode:
- if prev_state != 'absent':
- # try to replace atomically
- tmppath = '/'.join([os.path.dirname(path), ".%s.%s.tmp" % (os.getpid(),time.time())])
- try:
- if prev_state == 'directory' and (state == 'hard' or state == 'link'):
- os.rmdir(path)
- if state == 'hard':
- os.link(src,tmppath)
- else:
- os.symlink(src, tmppath)
- os.rename(tmppath, path)
- except OSError, e:
- if os.path.exists(tmppath):
- os.unlink(tmppath)
- module.fail_json(path=path, msg='Error while replacing: %s' % str(e))
- else:
- try:
- if state == 'hard':
- os.link(src,path)
- else:
- os.symlink(src, path)
- except OSError, e:
- module.fail_json(path=path, msg='Error while linking: %s' % str(e))
-
- if module.check_mode and not os.path.exists(path):
- module.exit_json(dest=path, src=src, changed=changed)
-
- changed = module.set_fs_attributes_if_different(file_args, changed)
- module.exit_json(dest=path, src=src, changed=changed)
-
- elif state == 'touch':
- if not module.check_mode:
-
- if prev_state == 'absent':
- try:
- open(path, 'w').close()
- except OSError, e:
- module.fail_json(path=path, msg='Error, could not touch target: %s' % str(e))
- elif prev_state in ['file', 'directory']:
- try:
- os.utime(path, None)
- except OSError, e:
- module.fail_json(path=path, msg='Error while touching existing target: %s' % str(e))
- else:
- module.fail_json(msg='Cannot touch other than files and directories')
- try:
- module.set_fs_attributes_if_different(file_args, True)
- except SystemExit, e:
- if e.code:
- # We take this to mean that fail_json() was called from
- # somewhere in basic.py
- if prev_state == 'absent':
- # If we just created the file we can safely remove it
- os.remove(path)
- raise e
-
- module.exit_json(dest=path, changed=True)
-
- module.fail_json(path=path, msg='unexpected position reached')
-
-# import module snippets
-from ansible.module_utils.basic import *
-main()
-
diff --git a/files/ini_file b/files/ini_file
deleted file mode 100644
index 83a980f5..00000000
--- a/files/ini_file
+++ /dev/null
@@ -1,207 +0,0 @@
-#!/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.
- - Comments are discarded when the source file is read, and therefore will not
- show up in the destination file.
-version_added: "0.9"
-options:
- 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
- default: null
- value:
- description:
- - the string value to be associated with an I(option). May be omitted when removing an I(option).
- required: false
- default: null
- 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.
- - 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.
-requirements: [ ConfigParser ]
-author: Jan-Piet Mens
-'''
-
-EXAMPLES = '''
-# Ensure "fav=lemonade is in section "[drinks]" in specified file
-- ini_file: dest=/etc/conf section=drinks option=fav value=lemonade mode=0600 backup=yes
-
-- ini_file: dest=/etc/anotherconf
- section=drinks
- option=temperature
- value=cold
- backup=yes
-'''
-
-import ConfigParser
-import sys
-
-# ==============================================================
-# do_ini
-
-def do_ini(module, filename, section=None, option=None, value=None, state='present', backup=False):
-
- changed = False
- if (sys.version_info[0] == 2 and sys.version_info[1] >= 7) or sys.version_info[0] >= 3:
- cp = ConfigParser.ConfigParser(allow_no_value=True)
- else:
- cp = ConfigParser.ConfigParser()
- cp.optionxform = identity
-
- 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':
-
- # DEFAULT section is always there by DEFAULT, so never try to add it.
- if cp.has_section(section) == False and section.upper() != 'DEFAULT':
-
- 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.NoSectionError:
- 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
-
-# ==============================================================
-# identity
-
-def identity(arg):
- """
- This function simply returns its argument. It serves as a
- replacement for ConfigParser.optionxform, which by default
- changes arguments to lower case. The identity function is a
- better choice than str() or unicode(), because it is
- encoding-agnostic.
- """
- return arg
-
-# ==============================================================
-# main
-
-def main():
-
- module = AnsibleModule(
- argument_spec = dict(
- dest = dict(required=True),
- section = dict(required=True),
- option = dict(required=False),
- value = dict(required=False),
- backup = dict(default='no', type='bool'),
- state = dict(default='present', choices=['present', 'absent'])
- ),
- add_file_common_args = True
- )
-
- 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.params['backup']
-
- changed = do_ini(module, dest, section, option, value, state, backup)
-
- file_args = module.load_file_common_arguments(module.params)
- changed = module.set_fs_attributes_if_different(file_args, changed)
-
- # Mission complete
- module.exit_json(dest=dest, changed=changed, msg="OK")
-
-# import module snippets
-from ansible.module_utils.basic import *
-main()
diff --git a/files/lineinfile b/files/lineinfile
deleted file mode 100644
index 12f8dc89..00000000
--- a/files/lineinfile
+++ /dev/null
@@ -1,400 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2012, Daniel Hokka Zakrisson <daniel@hozac.com>
-# (c) 2014, Ahti Kitsik <ak@ahtik.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 pipes
-import re
-import os
-import tempfile
-
-DOCUMENTATION = """
----
-module: lineinfile
-author: Daniel Hokka Zakrisson, Ahti Kitsik
-short_description: Ensure a particular line is in a file, or replace an
- existing line using a back-referenced regular expression.
-description:
- - This module will search a file for a line, and ensure that it is present or absent.
- - This is primarily useful when you want to change a single line in a
- file only. For other cases, see the M(copy) or M(template) modules.
-version_added: "0.7"
-options:
- dest:
- required: true
- aliases: [ name, destfile ]
- description:
- - The file to modify.
- regexp:
- required: false
- version_added: 1.7
- description:
- - The regular expression to look for in every line of the file. For
- C(state=present), the pattern to replace if found; only the last line
- found will be replaced. For C(state=absent), the pattern of the line
- to remove. Uses Python regular expressions; see
- U(http://docs.python.org/2/library/re.html).
- state:
- required: false
- choices: [ present, absent ]
- default: "present"
- aliases: []
- description:
- - Whether the line should be there or not.
- line:
- required: false
- description:
- - Required for C(state=present). The line to insert/replace into the
- file. If C(backrefs) is set, may contain backreferences that will get
- expanded with the C(regexp) capture groups if the regexp matches. The
- backreferences should be double escaped (see examples).
- backrefs:
- required: false
- default: "no"
- choices: [ "yes", "no" ]
- version_added: "1.1"
- description:
- - Used with C(state=present). If set, line can contain backreferences
- (both positional and named) that will get populated if the C(regexp)
- matches. This flag changes the operation of the module slightly;
- C(insertbefore) and C(insertafter) will be ignored, and if the C(regexp)
- doesn't match anywhere in the file, the file will be left unchanged.
- If the C(regexp) does match, the last matching line will be replaced by
- the expanded line parameter.
- insertafter:
- required: false
- default: EOF
- description:
- - Used with C(state=present). If specified, the line will be inserted
- after the specified regular expression. A special value is
- available; C(EOF) for inserting the line at the end of the file.
- May not be used with C(backrefs).
- choices: [ 'EOF', '*regex*' ]
- insertbefore:
- required: false
- version_added: "1.1"
- description:
- - Used with C(state=present). If specified, the line will be inserted
- before the specified regular expression. A value is available;
- C(BOF) for inserting the line at the beginning of the file.
- May not be used with C(backrefs).
- choices: [ 'BOF', '*regex*' ]
- create:
- required: false
- choices: [ "yes", "no" ]
- default: "no"
- description:
- - Used with C(state=present). If specified, the file will be created
- if it does not already exist. By default it will fail if the file
- is missing.
- backup:
- required: false
- default: "no"
- choices: [ "yes", "no" ]
- description:
- - Create a backup file including the timestamp information so you can
- get the original file back if you somehow clobbered it incorrectly.
- validate:
- required: false
- description:
- - validation to run before copying into place.
- Use %s in the command to indicate the current file to validate.
- The command is passed securely so shell features like
- expansion and pipes won't work.
- required: false
- default: None
- version_added: "1.4"
- others:
- description:
- - All arguments accepted by the M(file) module also work here.
- required: false
-"""
-
-EXAMPLES = r"""
-- lineinfile: dest=/etc/selinux/config regexp=^SELINUX= line=SELINUX=disabled
-
-- lineinfile: dest=/etc/sudoers state=absent regexp="^%wheel"
-
-- lineinfile: dest=/etc/hosts regexp='^127\.0\.0\.1' line='127.0.0.1 localhost' owner=root group=root mode=0644
-
-- lineinfile: dest=/etc/httpd/conf/httpd.conf regexp="^Listen " insertafter="^#Listen " line="Listen 8080"
-
-- lineinfile: dest=/etc/services regexp="^# port for http" insertbefore="^www.*80/tcp" line="# port for http by default"
-
-# Add a line to a file if it does not exist, without passing regexp
-- lineinfile: dest=/tmp/testfile line="192.168.1.99 foo.lab.net foo"
-
-# Fully quoted because of the ': ' on the line. See the Gotchas in the YAML docs.
-- lineinfile: "dest=/etc/sudoers state=present regexp='^%wheel' line='%wheel ALL=(ALL) NOPASSWD: ALL'"
-
-- lineinfile: dest=/opt/jboss-as/bin/standalone.conf regexp='^(.*)Xms(\d+)m(.*)$' line='\1Xms${xms}m\3' backrefs=yes
-
-# Validate a the sudoers file before saving
-- lineinfile: dest=/etc/sudoers state=present regexp='^%ADMIN ALL\=' line='%ADMIN ALL=(ALL) NOPASSWD:ALL' validate='visudo -cf %s'
-"""
-
-def write_changes(module,lines,dest):
-
- tmpfd, tmpfile = tempfile.mkstemp()
- f = os.fdopen(tmpfd,'wb')
- f.writelines(lines)
- f.close()
-
- validate = module.params.get('validate', None)
- valid = not validate
- if validate:
- if "%s" not in validate:
- module.fail_json(msg="validate must contain %%s: %s" % (validate))
- (rc, out, err) = module.run_command(validate % tmpfile)
- valid = rc == 0
- if rc != 0:
- module.fail_json(msg='failed to validate: '
- 'rc:%s error:%s' % (rc,err))
- if valid:
- module.atomic_move(tmpfile, os.path.realpath(dest))
-
-def check_file_attrs(module, changed, message):
-
- file_args = module.load_file_common_arguments(module.params)
- if module.set_fs_attributes_if_different(file_args, False):
-
- if changed:
- message += " and "
- changed = True
- message += "ownership, perms or SE linux context changed"
-
- return message, changed
-
-
-def present(module, dest, regexp, line, insertafter, insertbefore, create,
- backup, backrefs):
-
- if not os.path.exists(dest):
- if not create:
- module.fail_json(rc=257, msg='Destination %s does not exist !' % dest)
- destpath = os.path.dirname(dest)
- if not os.path.exists(destpath):
- os.makedirs(destpath)
- lines = []
- else:
- f = open(dest, 'rb')
- lines = f.readlines()
- f.close()
-
- msg = ""
-
- if regexp is not None:
- mre = re.compile(regexp)
-
- if insertafter not in (None, 'BOF', 'EOF'):
- insre = re.compile(insertafter)
- elif insertbefore not in (None, 'BOF'):
- insre = re.compile(insertbefore)
- else:
- insre = None
-
- # index[0] is the line num where regexp has been found
- # index[1] is the line num where insertafter/inserbefore has been found
- index = [-1, -1]
- m = None
- for lineno, cur_line in enumerate(lines):
- if regexp is not None:
- match_found = mre.search(cur_line)
- else:
- match_found = line == cur_line.rstrip('\r\n')
- if match_found:
- index[0] = lineno
- m = match_found
- elif insre is not None and insre.search(cur_line):
- if insertafter:
- # + 1 for the next line
- index[1] = lineno + 1
- if insertbefore:
- # + 1 for the previous line
- index[1] = lineno
-
- msg = ''
- changed = False
- # Regexp matched a line in the file
- if index[0] != -1:
- if backrefs:
- new_line = m.expand(line)
- else:
- # Don't do backref expansion if not asked.
- new_line = line
-
- if lines[index[0]] != new_line + os.linesep:
- lines[index[0]] = new_line + os.linesep
- msg = 'line replaced'
- changed = True
- elif backrefs:
- # Do absolutely nothing, since it's not safe generating the line
- # without the regexp matching to populate the backrefs.
- pass
- # Add it to the beginning of the file
- elif insertbefore == 'BOF' or insertafter == 'BOF':
- lines.insert(0, line + os.linesep)
- msg = 'line added'
- changed = True
- # Add it to the end of the file if requested or
- # if insertafter=/insertbefore didn't match anything
- # (so default behaviour is to add at the end)
- elif insertafter == 'EOF':
-
- # If the file is not empty then ensure there's a newline before the added line
- if len(lines)>0 and not (lines[-1].endswith('\n') or lines[-1].endswith('\r')):
- lines.append(os.linesep)
-
- lines.append(line + os.linesep)
- msg = 'line added'
- changed = True
- # Do nothing if insert* didn't match
- elif index[1] == -1:
- pass
- # insert* matched, but not the regexp
- else:
- lines.insert(index[1], line + os.linesep)
- msg = 'line added'
- changed = True
-
- backupdest = ""
- if changed and not module.check_mode:
- if backup and os.path.exists(dest):
- backupdest = module.backup_local(dest)
- write_changes(module, lines, dest)
-
- msg, changed = check_file_attrs(module, changed, msg)
- module.exit_json(changed=changed, msg=msg, backup=backupdest)
-
-
-def absent(module, dest, regexp, line, backup):
-
- if not os.path.exists(dest):
- module.exit_json(changed=False, msg="file not present")
-
- msg = ""
-
- f = open(dest, 'rb')
- lines = f.readlines()
- f.close()
- if regexp is not None:
- cre = re.compile(regexp)
- found = []
-
- def matcher(cur_line):
- if regexp is not None:
- match_found = cre.search(cur_line)
- else:
- match_found = line == cur_line.rstrip('\r\n')
- if match_found:
- found.append(cur_line)
- return not match_found
-
- lines = filter(matcher, lines)
- changed = len(found) > 0
- backupdest = ""
- if changed and not module.check_mode:
- if backup:
- backupdest = module.backup_local(dest)
- write_changes(module, lines, dest)
-
- if changed:
- msg = "%s line(s) removed" % len(found)
-
- msg, changed = check_file_attrs(module, changed, msg)
- module.exit_json(changed=changed, found=len(found), msg=msg, backup=backupdest)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- dest=dict(required=True, aliases=['name', 'destfile']),
- state=dict(default='present', choices=['absent', 'present']),
- regexp=dict(default=None),
- line=dict(aliases=['value']),
- insertafter=dict(default=None),
- insertbefore=dict(default=None),
- backrefs=dict(default=False, type='bool'),
- create=dict(default=False, type='bool'),
- backup=dict(default=False, type='bool'),
- validate=dict(default=None, type='str'),
- ),
- mutually_exclusive=[['insertbefore', 'insertafter']],
- add_file_common_args=True,
- supports_check_mode=True
- )
-
- params = module.params
- create = module.params['create']
- backup = module.params['backup']
- backrefs = module.params['backrefs']
- dest = os.path.expanduser(params['dest'])
-
-
- if os.path.isdir(dest):
- module.fail_json(rc=256, msg='Destination %s is a directory !' % dest)
-
- if params['state'] == 'present':
- if backrefs and params['regexp'] is None:
- module.fail_json(msg='regexp= is required with backrefs=true')
-
- if params.get('line', None) is None:
- module.fail_json(msg='line= is required with state=present')
-
- # Deal with the insertafter default value manually, to avoid errors
- # because of the mutually_exclusive mechanism.
- ins_bef, ins_aft = params['insertbefore'], params['insertafter']
- if ins_bef is None and ins_aft is None:
- ins_aft = 'EOF'
-
- line = params['line']
-
- # The safe_eval call will remove some quoting, but not others,
- # so we need to know if we should specifically unquote it.
- should_unquote = not is_quoted(line)
-
- # always add one layer of quotes
- line = "'%s'" % line
-
- # Replace escape sequences like '\n' while being sure
- # not to replace octal escape sequences (\ooo) since they
- # match the backref syntax.
- if backrefs:
- line = re.sub(r'(\\[0-9]{1,3})', r'\\\1', line)
- line = module.safe_eval(line)
-
- # Now remove quotes around the string, if needed after
- # removing the layer we added above
- line = unquote(line)
- if should_unquote:
- line = unquote(line)
-
- present(module, dest, params['regexp'], line,
- ins_aft, ins_bef, create, backup, backrefs)
- else:
- if params['regexp'] is None and params.get('line', None) is None:
- module.fail_json(msg='one of line= or regexp= is required with state=absent')
-
- absent(module, dest, params['regexp'], params.get('line', None), backup)
-
-# import module snippets
-from ansible.module_utils.basic import *
-from ansible.module_utils.splitter import *
-
-main()
diff --git a/files/replace b/files/replace
deleted file mode 100644
index 57b522dd..00000000
--- a/files/replace
+++ /dev/null
@@ -1,162 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2013, Evan Kaufman <evan@digitalflophouse.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 re
-import os
-import tempfile
-
-DOCUMENTATION = """
----
-module: replace
-author: Evan Kaufman
-short_description: Replace all instances of a particular string in a
- file using a back-referenced regular expression.
-description:
- - This module will replace all instances of a pattern within a file.
- - It is up to the user to maintain idempotence by ensuring that the
- same pattern would never match any replacements made.
-version_added: "1.6"
-options:
- dest:
- required: true
- aliases: [ name, destfile ]
- description:
- - The file to modify.
- regexp:
- required: true
- description:
- - The regular expression to look for in the contents of the file.
- Uses Python regular expressions; see
- U(http://docs.python.org/2/library/re.html).
- Uses multiline mode, which means C(^) and C($) match the beginning
- and end respectively of I(each line) of the file.
- replace:
- required: false
- description:
- - The string to replace regexp matches. May contain backreferences
- that will get expanded with the regexp capture groups if the regexp
- matches. If not set, matches are removed entirely.
- backup:
- required: false
- default: "no"
- choices: [ "yes", "no" ]
- description:
- - Create a backup file including the timestamp information so you can
- get the original file back if you somehow clobbered it incorrectly.
- validate:
- required: false
- description:
- - validation to run before copying into place
- required: false
- default: None
- others:
- description:
- - All arguments accepted by the M(file) module also work here.
- required: false
-"""
-
-EXAMPLES = r"""
-- replace: dest=/etc/hosts regexp='(\s+)old\.host\.name(\s+.*)?$' replace='\1new.host.name\2' backup=yes
-
-- replace: dest=/home/jdoe/.ssh/known_hosts regexp='^old\.host\.name[^\n]*\n' owner=jdoe group=jdoe mode=644
-
-- replace: dest=/etc/apache/ports regexp='^(NameVirtualHost|Listen)\s+80\s*$' replace='\1 127.0.0.1:8080' validate='/usr/sbin/apache2ctl -f %s -t'
-"""
-
-def write_changes(module,contents,dest):
-
- tmpfd, tmpfile = tempfile.mkstemp()
- f = os.fdopen(tmpfd,'wb')
- f.write(contents)
- f.close()
-
- validate = module.params.get('validate', None)
- valid = not validate
- if validate:
- if "%s" not in validate:
- module.fail_json(msg="validate must contain %%s: %s" % (validate))
- (rc, out, err) = module.run_command(validate % tmpfile)
- valid = rc == 0
- if rc != 0:
- module.fail_json(msg='failed to validate: '
- 'rc:%s error:%s' % (rc,err))
- if valid:
- module.atomic_move(tmpfile, dest)
-
-def check_file_attrs(module, changed, message):
-
- file_args = module.load_file_common_arguments(module.params)
- if module.set_file_attributes_if_different(file_args, False):
-
- if changed:
- message += " and "
- changed = True
- message += "ownership, perms or SE linux context changed"
-
- return message, changed
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- dest=dict(required=True, aliases=['name', 'destfile']),
- regexp=dict(required=True),
- replace=dict(default='', type='str'),
- backup=dict(default=False, type='bool'),
- validate=dict(default=None, type='str'),
- ),
- add_file_common_args=True,
- supports_check_mode=True
- )
-
- params = module.params
- dest = os.path.expanduser(params['dest'])
-
- if os.path.isdir(dest):
- module.fail_json(rc=256, msg='Destination %s is a directory !' % dest)
-
- if not os.path.exists(dest):
- module.fail_json(rc=257, msg='Destination %s does not exist !' % dest)
- else:
- f = open(dest, 'rb')
- contents = f.read()
- f.close()
-
- mre = re.compile(params['regexp'], re.MULTILINE)
- result = re.subn(mre, params['replace'], contents, 0)
-
- if result[1] > 0 and contents != result[0]:
- msg = '%s replacements made' % result[1]
- changed = True
- else:
- msg = ''
- changed = False
-
- if changed and not module.check_mode:
- if params['backup'] and os.path.exists(dest):
- module.backup_local(dest)
- write_changes(module, result[0], dest)
-
- msg, changed = check_file_attrs(module, changed, msg)
- module.exit_json(changed=changed, msg=msg)
-
-# this is magic, see lib/ansible/module_common.py
-#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
-
-main()
diff --git a/files/stat b/files/stat
deleted file mode 100644
index 8c717a39..00000000
--- a/files/stat
+++ /dev/null
@@ -1,152 +0,0 @@
-#!/usr/bin/python
-# 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: stat
-version_added: "1.3"
-short_description: retrieve file or file system status
-description:
- - Retrieves facts for a file similar to the linux/unix 'stat' command.
-options:
- path:
- description:
- - The full path of the file/object to get the facts of
- required: true
- default: null
- aliases: []
- follow:
- description:
- - Whether to follow symlinks
- required: false
- default: no
- aliases: []
- get_md5:
- description:
- - Whether to return the md5 sum of the file
- required: false
- default: yes
- aliases: []
-author: Bruce Pennypacker
-'''
-
-EXAMPLES = '''
-# Obtain the stats of /etc/foo.conf, and check that the file still belongs
-# to 'root'. Fail otherwise.
-- stat: path=/etc/foo.conf
- register: st
-- fail: msg="Whoops! file ownership has changed"
- when: st.stat.pw_name != 'root'
-
-# Determine if a path exists and is a directory. Note we need to test
-# both that p.stat.isdir actually exists, and also that it's set to true.
-- stat: path=/path/to/something
- register: p
-- debug: msg="Path exists and is a directory"
- when: p.stat.isdir is defined and p.stat.isdir == true
-
-# Don't do md5 checksum
-- stat: path=/path/to/myhugefile get_md5=no
-'''
-
-import os
-import sys
-from stat import *
-import pwd
-
-def main():
- module = AnsibleModule(
- argument_spec = dict(
- path = dict(required=True),
- follow = dict(default='no', type='bool'),
- get_md5 = dict(default='yes', type='bool')
- ),
- supports_check_mode = True
- )
-
- path = module.params.get('path')
- path = os.path.expanduser(path)
- follow = module.params.get('follow')
- get_md5 = module.params.get('get_md5')
-
- try:
- if follow:
- st = os.stat(path)
- else:
- st = os.lstat(path)
- except OSError, e:
- if e.errno == errno.ENOENT:
- d = { 'exists' : False }
- module.exit_json(changed=False, stat=d)
-
- module.fail_json(msg = e.strerror)
-
- mode = st.st_mode
-
- # back to ansible
- d = {
- 'exists' : True,
- 'mode' : "%04o" % S_IMODE(mode),
- 'isdir' : S_ISDIR(mode),
- 'ischr' : S_ISCHR(mode),
- 'isblk' : S_ISBLK(mode),
- 'isreg' : S_ISREG(mode),
- 'isfifo' : S_ISFIFO(mode),
- 'islnk' : S_ISLNK(mode),
- 'issock' : S_ISSOCK(mode),
- 'uid' : st.st_uid,
- 'gid' : st.st_gid,
- 'size' : st.st_size,
- 'inode' : st.st_ino,
- 'dev' : st.st_dev,
- 'nlink' : st.st_nlink,
- 'atime' : st.st_atime,
- 'mtime' : st.st_mtime,
- 'ctime' : st.st_ctime,
- 'wusr' : bool(mode & stat.S_IWUSR),
- 'rusr' : bool(mode & stat.S_IRUSR),
- 'xusr' : bool(mode & stat.S_IXUSR),
- 'wgrp' : bool(mode & stat.S_IWGRP),
- 'rgrp' : bool(mode & stat.S_IRGRP),
- 'xgrp' : bool(mode & stat.S_IXGRP),
- 'woth' : bool(mode & stat.S_IWOTH),
- 'roth' : bool(mode & stat.S_IROTH),
- 'xoth' : bool(mode & stat.S_IXOTH),
- 'isuid' : bool(mode & stat.S_ISUID),
- 'isgid' : bool(mode & stat.S_ISGID),
- }
-
- if S_ISLNK(mode):
- d['lnk_source'] = os.path.realpath(path)
-
- if S_ISREG(mode) and get_md5 and os.access(path,os.R_OK):
- d['md5'] = module.md5(path)
-
-
- try:
- pw = pwd.getpwuid(st.st_uid)
-
- d['pw_name'] = pw.pw_name
- except:
- pass
-
-
- module.exit_json(changed=False, stat=d)
-
-# import module snippets
-from ansible.module_utils.basic import *
-
-main()
diff --git a/files/synchronize b/files/synchronize
deleted file mode 100644
index 842dd863..00000000
--- a/files/synchronize
+++ /dev/null
@@ -1,345 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2012-2013, Timothy Appnel <tim@appnel.com>
-#
-# 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: synchronize
-version_added: "1.4"
-short_description: Uses rsync to make synchronizing file paths in your playbooks quick and easy.
-description:
- - This is a wrapper around rsync. Of course you could just use the command action to call rsync yourself, but you also have to add a fair number of boilerplate options and host facts. You still may need to call rsync directly via C(command) or C(shell) depending on your use case. The synchronize action is meant to do common things with C(rsync) easily. It does not provide access to the full power of rsync, but does make most invocations easier to follow.
-options:
- src:
- description:
- - Path on the source machine that will be synchronized to the destination; The path can be absolute or relative.
- required: true
- dest:
- description:
- - Path on the destination machine that will be synchronized from the source; The path can be absolute or relative.
- required: true
- dest_port:
- description:
- - Port number for ssh on the destination host. The ansible_ssh_port inventory var takes precedence over this value.
- default: 22
- version_added: "1.5"
- mode:
- description:
- - Specify the direction of the synchroniztion. In push mode the localhost or delegate is the source; In pull mode the remote host in context is the source.
- required: false
- choices: [ 'push', 'pull' ]
- default: 'push'
- archive:
- description:
- - Mirrors the rsync archive flag, enables recursive, links, perms, times, owner, group flags and -D.
- choices: [ 'yes', 'no' ]
- default: 'yes'
- required: false
- checksum:
- description:
- - Skip based on checksum, rather than mod-time & size; Note that that "archive" option is still enabled by default - the "checksum" option will not disable it.
- choices: [ 'yes', 'no' ]
- default: 'no'
- required: false
- version_added: "1.6"
- compress:
- description:
- - Compress file data during the transfer. In most cases, leave this enabled unless it causes problems.
- choices: [ 'yes', 'no' ]
- default: 'yes'
- required: false
- version_added: "1.7"
- existing_only:
- description:
- - Skip creating new files on receiver.
- choices: [ 'yes', 'no' ]
- default: 'no'
- required: false
- version_added: "1.5"
- delete:
- description:
- - Delete files that don't exist (after transfer, not before) in the C(src) path. This option requires C(recursive=yes).
- choices: [ 'yes', 'no' ]
- default: 'no'
- required: false
- dirs:
- description:
- - Transfer directories without recursing
- choices: [ 'yes', 'no' ]
- default: 'no'
- required: false
- recursive:
- description:
- - Recurse into directories.
- choices: [ 'yes', 'no' ]
- default: the value of the archive option
- required: false
- links:
- description:
- - Copy symlinks as symlinks.
- choices: [ 'yes', 'no' ]
- default: the value of the archive option
- required: false
- copy_links:
- description:
- - Copy symlinks as the item that they point to (the referent) is copied, rather than the symlink.
- choices: [ 'yes', 'no' ]
- default: 'no'
- required: false
- perms:
- description:
- - Preserve permissions.
- choices: [ 'yes', 'no' ]
- default: the value of the archive option
- required: false
- times:
- description:
- - Preserve modification times
- choices: [ 'yes', 'no' ]
- default: the value of the archive option
- required: false
- owner:
- description:
- - Preserve owner (super user only)
- choices: [ 'yes', 'no' ]
- default: the value of the archive option
- required: false
- group:
- description:
- - Preserve group
- choices: [ 'yes', 'no' ]
- default: the value of the archive option
- required: false
- rsync_path:
- description:
- - Specify the rsync command to run on the remote machine. See C(--rsync-path) on the rsync man page.
- required: false
- rsync_timeout:
- description:
- - Specify a --timeout for the rsync command in seconds.
- default: 0
- required: false
- set_remote_user:
- description:
- - put user@ for the remote paths. If you have a custom ssh config to define the remote user for a host
- that does not match the inventory user, you should set this parameter to "no".
- default: yes
- rsync_opts:
- description:
- - Specify additional rsync options by passing in an array.
- default:
- required: false
- version_added: "1.6"
-notes:
- - Inspect the verbose output to validate the destination user/host/path
- are what was expected.
- - The remote user for the dest path will always be the remote_user, not
- the sudo_user.
- - Expect that dest=~/x will be ~<remote_user>/x even if using sudo.
- - To exclude files and directories from being synchronized, you may add
- C(.rsync-filter) files to the source directory.
-
-
-author: Timothy Appnel
-'''
-
-EXAMPLES = '''
-# Synchronization of src on the control machine to dest on the remote hosts
-synchronize: src=some/relative/path dest=/some/absolute/path
-
-# Synchronization without any --archive options enabled
-synchronize: src=some/relative/path dest=/some/absolute/path archive=no
-
-# Synchronization with --archive options enabled except for --recursive
-synchronize: src=some/relative/path dest=/some/absolute/path recursive=no
-
-# Synchronization with --archive options enabled except for --times, with --checksum option enabled
-synchronize: src=some/relative/path dest=/some/absolute/path checksum=yes times=no
-
-# Synchronization without --archive options enabled except use --links
-synchronize: src=some/relative/path dest=/some/absolute/path archive=no links=yes
-
-# Synchronization of two paths both on the control machine
-local_action: synchronize src=some/relative/path dest=/some/absolute/path
-
-# Synchronization of src on the inventory host to the dest on the localhost in
-pull mode
-synchronize: mode=pull src=some/relative/path dest=/some/absolute/path
-
-# Synchronization of src on delegate host to dest on the current inventory host
-synchronize: >
- src=some/relative/path dest=/some/absolute/path
- delegate_to: delegate.host
-
-# Synchronize and delete files in dest on the remote host that are not found in src of localhost.
-synchronize: src=some/relative/path dest=/some/absolute/path delete=yes
-
-# Synchronize using an alternate rsync command
-synchronize: src=some/relative/path dest=/some/absolute/path rsync_path="sudo rsync"
-
-# Example .rsync-filter file in the source directory
-- var # exclude any path whose last part is 'var'
-- /var # exclude any path starting with 'var' starting at the source directory
-+ /var/conf # include /var/conf even though it was previously excluded
-
-# Synchronize passing in extra rsync options
-synchronize: src=/tmp/helloworld dest=/var/www/helloword rsync_opts=--no-motd,--exclude=.git
-'''
-
-
-def main():
- module = AnsibleModule(
- argument_spec = dict(
- src = dict(required=True),
- dest = dict(required=True),
- dest_port = dict(default=22),
- delete = dict(default='no', type='bool'),
- private_key = dict(default=None),
- rsync_path = dict(default=None),
- archive = dict(default='yes', type='bool'),
- checksum = dict(default='no', type='bool'),
- compress = dict(default='yes', type='bool'),
- existing_only = dict(default='no', type='bool'),
- dirs = dict(default='no', type='bool'),
- recursive = dict(type='bool'),
- links = dict(type='bool'),
- copy_links = dict(type='bool'),
- perms = dict(type='bool'),
- times = dict(type='bool'),
- owner = dict(type='bool'),
- group = dict(type='bool'),
- set_remote_user = dict(default='yes', type='bool'),
- rsync_timeout = dict(type='int', default=0),
- rsync_opts = dict(type='list')
- ),
- supports_check_mode = True
- )
-
- source = '"' + module.params['src'] + '"'
- dest = '"' + module.params['dest'] + '"'
- dest_port = module.params['dest_port']
- delete = module.params['delete']
- private_key = module.params['private_key']
- rsync_path = module.params['rsync_path']
- rsync = module.params.get('local_rsync_path', 'rsync')
- rsync_timeout = module.params.get('rsync_timeout', 'rsync_timeout')
- archive = module.params['archive']
- checksum = module.params['checksum']
- compress = module.params['compress']
- existing_only = module.params['existing_only']
- dirs = module.params['dirs']
- # the default of these params depends on the value of archive
- recursive = module.params['recursive']
- links = module.params['links']
- copy_links = module.params['copy_links']
- perms = module.params['perms']
- times = module.params['times']
- owner = module.params['owner']
- group = module.params['group']
- rsync_opts = module.params['rsync_opts']
-
- cmd = '%s --delay-updates -FF' % rsync
- if compress:
- cmd = cmd + ' --compress'
- if rsync_timeout:
- cmd = cmd + ' --timeout=%s' % rsync_timeout
- if module.check_mode:
- cmd = cmd + ' --dry-run'
- if delete:
- cmd = cmd + ' --delete-after'
- if existing_only:
- cmd = cmd + ' --existing'
- if checksum:
- cmd = cmd + ' --checksum'
- if archive:
- cmd = cmd + ' --archive'
- if recursive is False:
- cmd = cmd + ' --no-recursive'
- if links is False:
- cmd = cmd + ' --no-links'
- if copy_links is True:
- cmd = cmd + ' --copy-links'
- if perms is False:
- cmd = cmd + ' --no-perms'
- if times is False:
- cmd = cmd + ' --no-times'
- if owner is False:
- cmd = cmd + ' --no-owner'
- if group is False:
- cmd = cmd + ' --no-group'
- else:
- if recursive is True:
- cmd = cmd + ' --recursive'
- if links is True:
- cmd = cmd + ' --links'
- if copy_links is True:
- cmd = cmd + ' --copy-links'
- if perms is True:
- cmd = cmd + ' --perms'
- if times is True:
- cmd = cmd + ' --times'
- if owner is True:
- cmd = cmd + ' --owner'
- if group is True:
- cmd = cmd + ' --group'
- if dirs:
- cmd = cmd + ' --dirs'
- if private_key is None:
- private_key = ''
- else:
- private_key = '-i '+ private_key
-
- ssh_opts = '-S none -o StrictHostKeyChecking=no'
- if dest_port != 22:
- cmd += " --rsh 'ssh %s %s -o Port=%s'" % (private_key, ssh_opts, dest_port)
- else:
- cmd += " --rsh 'ssh %s %s'" % (private_key, ssh_opts) # need ssh param
-
- if rsync_path:
- cmd = cmd + " --rsync-path=%s" % (rsync_path)
-
- if rsync_opts:
- cmd = cmd + " " + " ".join(rsync_opts)
-
- changed_marker = '<<CHANGED>>'
- cmd = cmd + " --out-format='" + changed_marker + "%i %n%L'"
-
- # expand the paths
- if '@' not in source:
- source = os.path.expanduser(source)
- if '@' not in dest:
- dest = os.path.expanduser(dest)
-
- cmd = ' '.join([cmd, source, dest])
- cmdstr = cmd
- (rc, out, err) = module.run_command(cmd)
- if rc:
- return module.fail_json(msg=err, rc=rc, cmd=cmdstr)
- else:
- changed = changed_marker in out
- out_clean=out.replace(changed_marker,'')
- out_lines=out_clean.split('\n')
- while '' in out_lines:
- out_lines.remove('')
- return module.exit_json(changed=changed, msg=out_clean,
- rc=rc, cmd=cmdstr, stdout_lines=out_lines)
-
-# import module snippets
-from ansible.module_utils.basic import *
-
-main()
-
diff --git a/files/template b/files/template
deleted file mode 100644
index 7ba072fc..00000000
--- a/files/template
+++ /dev/null
@@ -1,66 +0,0 @@
-# this is a virtual module that is entirely implemented server side
-
-DOCUMENTATION = '''
----
-module: template
-version_added: historical
-short_description: Templates a file out to a remote server.
-description:
- - Templates are processed by the Jinja2 templating language
- (U(http://jinja.pocoo.org/docs/)) - documentation on the template
- formatting can be found in the Template Designer Documentation
- (U(http://jinja.pocoo.org/docs/templates/)).
- - "Six additional variables can be used in templates: C(ansible_managed)
- (configurable via the C(defaults) section of C(ansible.cfg)) contains a string
- which can be used to describe the template name, host, modification time of the
- template file and the owner uid, C(template_host) contains the node name of
- the template's machine, C(template_uid) the owner, C(template_path) the
- absolute path of the template, C(template_fullpath) is the absolute path of the
- template, and C(template_run_date) is the date that the template was rendered. Note that including
- a string that uses a date in the template will result in the template being marked 'changed'
- each time."
-options:
- src:
- description:
- - Path of a Jinja2 formatted template on the local server. This can be a relative or absolute path.
- required: true
- default: null
- aliases: []
- dest:
- description:
- - Location to render the template to on the remote machine.
- required: true
- default: null
- 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
- choices: [ "yes", "no" ]
- default: "no"
- validate:
- description:
- - The validation command to run before copying into place.
- - The path to the file to validate is passed in via '%s' which must be present as in the visudo example below.
- - validation to run before copying into place. The command is passed
- securely so shell features like expansion and pipes won't work.
- required: false
- default: ""
- version_added: "1.2"
-notes:
- - "Since Ansible version 0.9, templates are loaded with C(trim_blocks=True)."
-requirements: []
-author: Michael DeHaan
-extends_documentation_fragment: files
-'''
-
-EXAMPLES = '''
-# Example from Ansible Playbooks
-- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode=0644
-
-# The same example, but using symbolic modes equivalent to 0644
-- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode="u=rw,g=r,o=r"
-
-# Copy a new "sudoers" file into place, after passing validation with visudo
-- template: src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'
-'''
diff --git a/files/unarchive b/files/unarchive
deleted file mode 100644
index 657e4649..00000000
--- a/files/unarchive
+++ /dev/null
@@ -1,250 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
-# (c) 2013, Dylan Martin <dmartin@seattlecentral.edu>
-#
-# 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: unarchive
-version_added: 1.4
-short_description: Copies an archive to a remote location and unpack it
-description:
- - The M(unarchive) module copies an archive file from the local machine to a remote and unpacks it.
-options:
- src:
- description:
- - Local path to archive file to copy to the remote server; can be absolute or relative.
- required: true
- default: null
- dest:
- description:
- - Remote absolute path where the archive should be unpacked
- required: true
- default: null
- copy:
- description:
- - "if true, the file is copied from the 'master' to the target machine, otherwise, the plugin will look for src archive at the target machine."
- required: false
- choices: [ "yes", "no" ]
- default: "yes"
- creates:
- description:
- - a filename, when it already exists, this step will B(not) be run.
- required: no
- default: null
- version_added: "1.6"
-author: Dylan Martin
-todo:
- - detect changed/unchanged for .zip files
- - handle common unarchive args, like preserve owner/timestamp etc...
-notes:
- - requires C(tar)/C(unzip) command on target host
- - can handle I(gzip), I(bzip2) and I(xz) compressed as well as uncompressed tar files
- - detects type of archive automatically
- - uses tar's C(--diff arg) to calculate if changed or not. If this C(arg) is not
- supported, it will always unpack the archive
- - does not detect if a .zip file is different from destination - always unzips
- - existing files/directories in the destination which are not in the archive
- are not touched. This is the same behavior as a normal archive extraction
- - existing files/directories in the destination which are not in the archive
- are ignored for purposes of deciding if the archive should be unpacked or not
-'''
-
-EXAMPLES = '''
-# Example from Ansible Playbooks
-- unarchive: src=foo.tgz dest=/var/lib/foo
-
-# Unarchive a file that is already on the remote machine
-- unarchive: src=/tmp/foo.zip dest=/usr/local/bin copy=no
-'''
-
-import os
-
-
-# class to handle .zip files
-class ZipFile(object):
-
- def __init__(self, src, dest, module):
- self.src = src
- self.dest = dest
- self.module = module
- self.cmd_path = self.module.get_bin_path('unzip')
-
- def is_unarchived(self):
- return dict(unarchived=False)
-
- def unarchive(self):
- cmd = '%s -o "%s" -d "%s"' % (self.cmd_path, self.src, self.dest)
- rc, out, err = self.module.run_command(cmd)
- return dict(cmd=cmd, rc=rc, out=out, err=err)
-
- def can_handle_archive(self):
- if not self.cmd_path:
- return False
- cmd = '%s -l "%s"' % (self.cmd_path, self.src)
- rc, out, err = self.module.run_command(cmd)
- if rc == 0:
- return True
- return False
-
-
-# class to handle gzipped tar files
-class TgzFile(object):
-
- def __init__(self, src, dest, module):
- self.src = src
- self.dest = dest
- self.module = module
- self.cmd_path = self.module.get_bin_path('tar')
- self.zipflag = 'z'
-
- def is_unarchived(self):
- cmd = '%s -v -C "%s" --diff -%sf "%s"' % (self.cmd_path, self.dest, self.zipflag, self.src)
- rc, out, err = self.module.run_command(cmd)
- unarchived = (rc == 0)
- return dict(unarchived=unarchived, rc=rc, out=out, err=err, cmd=cmd)
-
- def unarchive(self):
- cmd = '%s -x%sf "%s"' % (self.cmd_path, self.zipflag, self.src)
- rc, out, err = self.module.run_command(cmd, cwd=self.dest)
- return dict(cmd=cmd, rc=rc, out=out, err=err)
-
- def can_handle_archive(self):
- if not self.cmd_path:
- return False
- cmd = '%s -t%sf "%s"' % (self.cmd_path, self.zipflag, self.src)
- rc, out, err = self.module.run_command(cmd)
- if rc == 0:
- if len(out.splitlines(True)) > 0:
- return True
- return False
-
-
-# class to handle tar files that aren't compressed
-class TarFile(TgzFile):
- def __init__(self, src, dest, module):
- self.src = src
- self.dest = dest
- self.module = module
- self.cmd_path = self.module.get_bin_path('tar')
- self.zipflag = ''
-
-
-# class to handle bzip2 compressed tar files
-class TarBzip(TgzFile):
- def __init__(self, src, dest, module):
- self.src = src
- self.dest = dest
- self.module = module
- self.cmd_path = self.module.get_bin_path('tar')
- self.zipflag = 'j'
-
-
-# class to handle xz compressed tar files
-class TarXz(TgzFile):
- def __init__(self, src, dest, module):
- self.src = src
- self.dest = dest
- self.module = module
- self.cmd_path = self.module.get_bin_path('tar')
- self.zipflag = 'J'
-
-
-# try handlers in order and return the one that works or bail if none work
-def pick_handler(src, dest, module):
- handlers = [TgzFile, ZipFile, TarFile, TarBzip, TarXz]
- for handler in handlers:
- obj = handler(src, dest, module)
- if obj.can_handle_archive():
- return obj
- module.fail_json(msg='Failed to find handler to unarchive. Make sure the required command to extract the file is installed.')
-
-
-def main():
- module = AnsibleModule(
- # not checking because of daisy chain to file module
- argument_spec = dict(
- src = dict(required=True),
- original_basename = dict(required=False), # used to handle 'dest is a directory' via template, a slight hack
- dest = dict(required=True),
- copy = dict(default=True, type='bool'),
- creates = dict(required=False),
- ),
- add_file_common_args=True,
- )
-
- src = os.path.expanduser(module.params['src'])
- dest = os.path.expanduser(module.params['dest'])
- copy = module.params['copy']
- creates = module.params['creates']
-
- # did tar file arrive?
- if not os.path.exists(src):
- if copy:
- module.fail_json(msg="Source '%s' failed to transfer" % src)
- else:
- module.fail_json(msg="Source '%s' does not exist" % src)
- if not os.access(src, os.R_OK):
- module.fail_json(msg="Source '%s' not readable" % src)
-
- if creates:
- # do not run the command if the line contains creates=filename
- # and the filename already exists. This allows idempotence
- # of command executions.
- v = os.path.expanduser(creates)
- if os.path.exists(v):
- module.exit_json(
- stdout="skipped, since %s exists" % v,
- skipped=True,
- changed=False,
- stderr=False,
- rc=0
- )
-
- # is dest OK to receive tar file?
- if not os.path.isdir(dest):
- module.fail_json(msg="Destination '%s' is not a directory" % dest)
- if not os.access(dest, os.W_OK):
- module.fail_json(msg="Destination '%s' not writable" % dest)
-
- handler = pick_handler(src, dest, module)
-
- res_args = dict(handler=handler.__class__.__name__, dest=dest, src=src)
-
- # do we need to do unpack?
- res_args['check_results'] = handler.is_unarchived()
- if res_args['check_results']['unarchived']:
- res_args['changed'] = False
- module.exit_json(**res_args)
-
- # do the unpack
- try:
- res_args['extract_results'] = handler.unarchive()
- if res_args['extract_results']['rc'] != 0:
- module.fail_json(msg="failed to unpack %s to %s" % (src, dest), **res_args)
- except IOError:
- module.fail_json(msg="failed to unpack %s to %s" % (src, dest))
-
- res_args['changed'] = True
-
- module.exit_json(**res_args)
-
-# import module snippets
-from ansible.module_utils.basic import *
-main()
diff --git a/files/xattr b/files/xattr
deleted file mode 100644
index 94115ae3..00000000
--- a/files/xattr
+++ /dev/null
@@ -1,206 +0,0 @@
-#!/usr/bin/python
-# 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: xattr
-version_added: "1.3"
-short_description: set/retrieve extended attributes
-description:
- - Manages filesystem user defined extended attributes, requires that they are enabled
- on the target filesystem and that the setfattr/getfattr utilities are present.
-options:
- name:
- required: true
- default: None
- aliases: ['path']
- description:
- - The full path of the file/object to get the facts of
- key:
- required: false
- default: None
- description:
- - The name of a specific Extended attribute key to set/retrieve
- value:
- required: false
- default: None
- description:
- - The value to set the named name/key to, it automatically sets the C(state) to 'set'
- state:
- required: false
- default: get
- choices: [ 'read', 'present', 'all', 'keys', 'absent' ]
- description:
- - defines which state you want to do.
- C(read) retrieves the current value for a C(key) (default)
- C(present) sets C(name) to C(value), default if value is set
- C(all) dumps all data
- C(keys) retrieves all keys
- C(absent) deletes the key
- follow:
- required: false
- default: yes
- choices: [ 'yes', 'no' ]
- description:
- - if yes, dereferences symlinks and sets/gets attributes on symlink target,
- otherwise acts on symlink itself.
-
-author: Brian Coca
-'''
-
-EXAMPLES = '''
-# Obtain the extended attributes of /etc/foo.conf
-- xattr: name=/etc/foo.conf
-
-# Sets the key 'foo' to value 'bar'
-- xattr: path=/etc/foo.conf key=user.foo value=bar
-
-# Removes the key 'foo'
-- xattr: name=/etc/foo.conf key=user.foo state=absent
-'''
-
-import operator
-
-def get_xattr_keys(module,path,follow):
- cmd = [ module.get_bin_path('getfattr', True) ]
- # prevents warning and not sure why it's not default
- cmd.append('--absolute-names')
- if not follow:
- cmd.append('-h')
- cmd.append(path)
-
- return _run_xattr(module,cmd)
-
-def get_xattr(module,path,key,follow):
-
- cmd = [ module.get_bin_path('getfattr', True) ]
- # prevents warning and not sure why it's not default
- cmd.append('--absolute-names')
- if not follow:
- cmd.append('-h')
- if key is None:
- cmd.append('-d')
- else:
- cmd.append('-n %s' % key)
- cmd.append(path)
-
- return _run_xattr(module,cmd,False)
-
-def set_xattr(module,path,key,value,follow):
-
- cmd = [ module.get_bin_path('setfattr', True) ]
- if not follow:
- cmd.append('-h')
- cmd.append('-n %s' % key)
- cmd.append('-v %s' % value)
- cmd.append(path)
-
- return _run_xattr(module,cmd)
-
-def rm_xattr(module,path,key,follow):
-
- cmd = [ module.get_bin_path('setfattr', True) ]
- if not follow:
- cmd.append('-h')
- cmd.append('-x %s' % key)
- cmd.append(path)
-
- return _run_xattr(module,cmd,False)
-
-def _run_xattr(module,cmd,check_rc=True):
-
- try:
- (rc, out, err) = module.run_command(' '.join(cmd), check_rc=check_rc)
- except Exception, e:
- module.fail_json(msg="%s!" % e.strerror)
-
- #result = {'raw': out}
- result = {}
- for line in out.splitlines():
- if re.match("^#", line) or line == "":
- pass
- elif re.search('=', line):
- (key, val) = line.split("=")
- result[key] = val.strip('"')
- else:
- result[line] = ''
- return result
-
-def main():
- module = AnsibleModule(
- argument_spec = dict(
- name = dict(required=True, aliases=['path']),
- key = dict(required=False, default=None),
- value = dict(required=False, default=None),
- state = dict(required=False, default='read', choices=[ 'read', 'present', 'all', 'keys', 'absent' ], type='str'),
- follow = dict(required=False, type='bool', default=True),
- ),
- supports_check_mode=True,
- )
- path = module.params.get('name')
- key = module.params.get('key')
- value = module.params.get('value')
- state = module.params.get('state')
- follow = module.params.get('follow')
-
- if not os.path.exists(path):
- module.fail_json(msg="path not found or not accessible!")
-
-
- changed=False
- msg = ""
- res = {}
-
- if key is None and state in ['present','absent']:
- module.fail_json(msg="%s needs a key parameter" % state)
-
- # All xattr must begin in user namespace
- if key is not None and not re.match('^user\.',key):
- key = 'user.%s' % key
-
-
- if (state == 'present' or value is not None):
- current=get_xattr(module,path,key,follow)
- if current is None or not key in current or value != current[key]:
- if not module.check_mode:
- res = set_xattr(module,path,key,value,follow)
- changed=True
- res=current
- msg="%s set to %s" % (key, value)
- elif state == 'absent':
- current=get_xattr(module,path,key,follow)
- if current is not None and key in current:
- if not module.check_mode:
- res = rm_xattr(module,path,key,follow)
- changed=True
- res=current
- msg="%s removed" % (key)
- elif state == 'keys':
- res=get_xattr_keys(module,path,follow)
- msg="returning all keys"
- elif state == 'all':
- res=get_xattr(module,path,None,follow)
- msg="dumping all"
- else:
- res=get_xattr(module,path,key,follow)
- msg="returning %s" % key
-
- module.exit_json(changed=changed, msg=msg, xattr=res)
-
-# import module snippets
-from ansible.module_utils.basic import *
-
-main()