From 1ad55ec9de630ca543bb2a59adf44af4e6d97820 Mon Sep 17 00:00:00 2001 From: Dag Wieers Date: Tue, 3 Jan 2017 13:47:00 +0100 Subject: [PATCH] Consistent path attribute for file-related modules Not all file-related modules consistently use "path" as the attribute to specify a single filename, some use "dest", others use "name". Most do have aliases for either "name" or "destfile". This change makes "path" the default attribute for (single) file-related modules, but also adds "dest" and "name" as aliases, so that people can use a consistent way of attributing paths, but also to ensure backward compatibility with existing playbooks. NOTE: The reason for changing this, is that it makes Ansible needlessly harder to use if you have to remember that e.g. the xattr module requires the name attribute, the lineinfile module requires a dest attribute, and the stat module requires a path attribute. --- lib/ansible/modules/files/acl.py | 29 ++--- lib/ansible/modules/files/blockinfile.py | 49 ++++---- lib/ansible/modules/files/ini_file.py | 32 ++--- lib/ansible/modules/files/lineinfile.py | 44 +++---- lib/ansible/modules/files/replace.py | 54 +++++---- lib/ansible/modules/files/xattr.py | 24 ++-- lib/ansible/modules/system/mount.py | 52 +++++---- .../modules/windows/win_lineinfile.ps1 | 109 ++++++++---------- lib/ansible/modules/windows/win_lineinfile.py | 22 ++-- 9 files changed, 215 insertions(+), 200 deletions(-) diff --git a/lib/ansible/modules/files/acl.py b/lib/ansible/modules/files/acl.py index ebd46d53c9..6f3bbfaf60 100644 --- a/lib/ansible/modules/files/acl.py +++ b/lib/ansible/modules/files/acl.py @@ -27,12 +27,12 @@ short_description: Sets and retrieves file ACL information. description: - Sets and retrieves file ACL information. options: - name: + path: required: true default: null description: - The full path of the file or object. - aliases: ['path'] + aliases: ['name'] state: required: false @@ -54,7 +54,7 @@ options: 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. + - 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 path is a file. entity: version_added: "1.5" @@ -70,7 +70,6 @@ options: description: - the entity type of the ACL to apply, see setfacl documentation for more info. - permissions: version_added: "1.5" required: false @@ -97,12 +96,13 @@ author: notes: - The "acl" module requires that acls are enabled on the target filesystem and that the setfacl and getfacl binaries are installed. - As of Ansible 2.0, this module only supports Linux distributions. + - As of Ansible 2.3, the I(name) option has been changed to I(path) as default, but I(name) still works as well. ''' EXAMPLES = ''' # Grant user Joe read access to a file - acl: - name: /etc/foo.conf + path: /etc/foo.conf entity: joe etype: user permissions: r @@ -110,14 +110,14 @@ EXAMPLES = ''' # Removes the acl for Joe on a specific file - acl: - name: /etc/foo.conf + path: /etc/foo.conf entity: joe etype: user state: absent # Sets default acl for joe on foo.d - acl: - name: /etc/foo.d + path: /etc/foo.d entity: joe etype: user permissions: rw @@ -126,13 +126,13 @@ EXAMPLES = ''' # Same as previous but using entry shorthand - acl: - name: /etc/foo.d + path: /etc/foo.d entry: "default:user:joe:rw-" state: present # Obtain the acl for a specific file - acl: - name: /etc/foo.conf + path: /etc/foo.conf register: acl_info ''' @@ -144,6 +144,10 @@ acl: sample: [ "user::rwx", "group::rwx", "other::rwx" ] ''' +import os + +# import module snippets +from ansible.module_utils.basic import AnsibleModule, get_platform def split_entry(entry): ''' splits entry and ensures normalized return''' @@ -258,7 +262,7 @@ def run_acl(module, cmd, check_rc=True): def main(): module = AnsibleModule( argument_spec=dict( - name=dict(required=True, aliases=['path'], type='path'), + path=dict(required=True, aliases=['name'], type='path'), entry=dict(required=False, type='str'), entity=dict(required=False, type='str', default=''), etype=dict( @@ -284,7 +288,7 @@ def main(): if get_platform().lower() not in ['linux', 'freebsd']: module.fail_json(msg="The acl module is not available on this system.") - path = module.params.get('name') + path = module.params.get('path') entry = module.params.get('entry') entity = module.params.get('entity') etype = module.params.get('etype') @@ -369,8 +373,5 @@ def main(): module.exit_json(changed=changed, msg=msg, acl=acl) -# import module snippets -from ansible.module_utils.basic import * - if __name__ == '__main__': main() diff --git a/lib/ansible/modules/files/blockinfile.py b/lib/ansible/modules/files/blockinfile.py index 0956935994..e243c1352e 100755 --- a/lib/ansible/modules/files/blockinfile.py +++ b/lib/ansible/modules/files/blockinfile.py @@ -36,15 +36,13 @@ version_added: '2.0' description: - This module will insert/update/remove a block of multi-line text surrounded by customizable marker lines. -notes: - - This module supports check mode. - - When using 'with_*' loops be aware that if you do not set a unique mark the block will be overwritten on each iteration. options: - dest: - aliases: [ name, destfile ] + path: + aliases: [ dest, destfile, name ] required: true description: - The file to modify. + - Before 2.3 this option was only usable as I(dest), I(destfile) and I(name). state: required: false choices: [ present, absent ] @@ -104,12 +102,17 @@ options: description: - 'This flag indicates that filesystem links, if they exist, should be followed.' version_added: "2.1" +notes: + - This module supports check mode. + - When using 'with_*' loops be aware that if you do not set a unique mark the block will be overwritten on each iteration. + - As of Ansible 2.3, the I(dest) option has been changed to I(path) as default, but I(dest) still works as well. """ EXAMPLES = r""" +# Before 2.3, option 'dest' or 'name' was used instead of 'path' - name: insert/update "Match User" configuration block in /etc/ssh/sshd_config blockinfile: - dest: /etc/ssh/sshd_config + path: /etc/ssh/sshd_config block: | Match User ansible-agent PasswordAuthentication no @@ -117,7 +120,7 @@ EXAMPLES = r""" - name: insert/update eth0 configuration stanza in /etc/network/interfaces (it might be better to copy files into /etc/network/interfaces.d/) blockinfile: - dest: /etc/network/interfaces + path: /etc/network/interfaces block: | iface eth0 inet static address 192.0.2.23 @@ -125,7 +128,7 @@ EXAMPLES = r""" - name: insert/update HTML surrounded by custom markers after line blockinfile: - dest: /var/www/html/index.html + path: /var/www/html/index.html marker: "" insertafter: "" content: | @@ -134,13 +137,13 @@ EXAMPLES = r""" - name: remove HTML as well as surrounding markers blockinfile: - dest: /var/www/html/index.html + path: /var/www/html/index.html marker: "" content: "" - name: Add mappings to /etc/hosts blockinfile: - dest: /etc/hosts + path: /etc/hosts block: | {{ item.ip }} {{ item.name }} marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.name }}" @@ -157,7 +160,7 @@ from ansible.module_utils.six import b from ansible.module_utils.basic import AnsibleModule from ansible.module_utils._text import to_bytes -def write_changes(module, contents, dest): +def write_changes(module, contents, path): tmpfd, tmpfile = tempfile.mkstemp() f = os.fdopen(tmpfd, 'wb') @@ -175,7 +178,7 @@ def write_changes(module, contents, dest): module.fail_json(msg='failed to validate: ' 'rc:%s error:%s' % (rc, err)) if valid: - module.atomic_move(tmpfile, dest, unsafe_writes=module.params['unsafe_writes']) + module.atomic_move(tmpfile, path, unsafe_writes=module.params['unsafe_writes']) def check_file_attrs(module, changed, message): @@ -194,7 +197,7 @@ def check_file_attrs(module, changed, message): def main(): module = AnsibleModule( argument_spec=dict( - dest=dict(required=True, aliases=['name', 'destfile'], type='path'), + path=dict(required=True, aliases=['dest', 'destfile', 'name'], type='path'), state=dict(default='present', choices=['absent', 'present']), marker=dict(default='# {mark} ANSIBLE MANAGED BLOCK', type='str'), block=dict(default='', type='str', aliases=['content']), @@ -210,23 +213,23 @@ def main(): ) params = module.params - dest = params['dest'] + path = params['path'] if module.boolean(params.get('follow', None)): - dest = os.path.realpath(dest) + path = os.path.realpath(path) - if os.path.isdir(dest): + if os.path.isdir(path): module.fail_json(rc=256, - msg='Destination %s is a directory !' % dest) + msg='Path %s is a directory !' % path) - path_exists = os.path.exists(dest) + path_exists = os.path.exists(path) if not path_exists: if not module.boolean(params['create']): module.fail_json(rc=257, - msg='Destination %s does not exist !' % dest) + msg='Path %s does not exist !' % path) original = None lines = [] else: - f = open(dest, 'rb') + f = open(path, 'rb') original = f.read() f.close() lines = original.splitlines() @@ -238,7 +241,7 @@ def main(): present = params['state'] == 'present' if not present and not path_exists: - module.exit_json(changed=False, msg="File not present") + module.exit_json(changed=False, msg="File %s not present" % path) if insertbefore is None and insertafter is None: insertafter = 'EOF' @@ -310,8 +313,8 @@ def main(): if changed and not module.check_mode: if module.boolean(params['backup']) and path_exists: - module.backup_local(dest) - write_changes(module, result, dest) + module.backup_local(path) + write_changes(module, result, path) if module.check_mode and not path_exists: module.exit_json(changed=changed, msg=msg) diff --git a/lib/ansible/modules/files/ini_file.py b/lib/ansible/modules/files/ini_file.py index 3bbce18409..5b0ef922de 100644 --- a/lib/ansible/modules/files/ini_file.py +++ b/lib/ansible/modules/files/ini_file.py @@ -36,11 +36,13 @@ description: - Before version 2.0, 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: + path: description: - - Path to the INI-style file; this file is created if required + - Path to the INI-style file; this file is created if required. + - Before 2.3 this option was only usable as I(dest). required: true default: null + aliases: ['dest'] section: description: - Section name in INI file. This is added if C(state=present) automatically when @@ -94,15 +96,18 @@ options: notes: - While it is possible to add an I(option) without specifying a I(value), this makes no sense. + - As of Ansible 2.3, the I(dest) option has been changed to I(path) as default, but + I(dest) still works as well. author: - "Jan-Piet Mens (@jpmens)" - "Ales Nosek (@noseka1)" ''' EXAMPLES = ''' -# Ensure "fav=lemonade is in section "[drinks]" in specified file -- ini_file: - dest: /etc/conf +# Before 2.3, option 'dest' was used instead of 'path' +- name: Ensure "fav=lemonade is in section "[drinks]" in specified file + ini_file: + path: /etc/conf section: drinks option: fav value: lemonade @@ -110,7 +115,7 @@ EXAMPLES = ''' backup: yes - ini_file: - dest: /etc/anotherconf + path: /etc/anotherconf section: drinks option: temperature value: cold @@ -120,6 +125,9 @@ EXAMPLES = ''' import os import re +# import module snippets +from ansible.module_utils.basic import AnsibleModule + # ============================================================== # match_opt @@ -258,7 +266,7 @@ def main(): module = AnsibleModule( argument_spec = dict( - dest = dict(required=True), + path = dict(required=True, aliases=['dest'], type='path'), section = dict(required=True), option = dict(required=False), value = dict(required=False), @@ -271,7 +279,7 @@ def main(): supports_check_mode = True ) - dest = os.path.expanduser(module.params['dest']) + path = os.path.expanduser(module.params['path']) section = module.params['section'] option = module.params['option'] value = module.params['value'] @@ -280,20 +288,18 @@ def main(): no_extra_spaces = module.params['no_extra_spaces'] create = module.params['create'] - (changed,backup_file,diff,msg) = do_ini(module, dest, section, option, value, state, backup, no_extra_spaces, create) + (changed,backup_file,diff,msg) = do_ini(module, path, section, option, value, state, backup, no_extra_spaces, create) - if not module.check_mode and os.path.exists(dest): + if not module.check_mode and os.path.exists(path): file_args = module.load_file_common_arguments(module.params) changed = module.set_fs_attributes_if_different(file_args, changed) - results = { 'changed': changed, 'msg': msg, 'dest': dest, 'diff': diff } + results = { 'changed': changed, 'msg': msg, 'path': path, 'diff': diff } if backup_file is not None: results['backup_file'] = backup_file # Mission complete module.exit_json(**results) -# import module snippets -from ansible.module_utils.basic import * if __name__ == '__main__': main() diff --git a/lib/ansible/modules/files/lineinfile.py b/lib/ansible/modules/files/lineinfile.py index 28202aa4ac..25329b554d 100644 --- a/lib/ansible/modules/files/lineinfile.py +++ b/lib/ansible/modules/files/lineinfile.py @@ -42,11 +42,12 @@ description: For other cases, see the M(copy) or M(template) modules. version_added: "0.7" options: - dest: + path: required: true - aliases: [ name, destfile ] + aliases: [ 'dest', 'destfile', 'name' ] description: - The file to modify. + - Before 2.3 this option was only usable as I(dest), I(destfile) and I(name). regexp: required: false version_added: 1.7 @@ -121,21 +122,24 @@ options: description: - All arguments accepted by the M(file) module also work here. required: false +notes: + - As of Ansible 2.3, the I(dest) option has been changed to I(path) as default, but I(dest) still works as well. """ EXAMPLES = r""" +# Before 2.3, option 'dest', 'destfile' or 'name' was used instead of 'path' - lineinfile: - dest: /etc/selinux/config + path: /etc/selinux/config regexp: '^SELINUX=' line: 'SELINUX=enforcing' - lineinfile: - dest: /etc/sudoers + path: /etc/sudoers state: absent regexp: '^%wheel' - lineinfile: - dest: /etc/hosts + path: /etc/hosts regexp: '^127\.0\.0\.1' line: '127.0.0.1 localhost' owner: root @@ -143,39 +147,39 @@ EXAMPLES = r""" mode: 0644 - lineinfile: - dest: /etc/httpd/conf/httpd.conf + path: /etc/httpd/conf/httpd.conf regexp: '^Listen ' insertafter: '^#Listen ' line: 'Listen 8080' - lineinfile: - dest: /etc/services + path: /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 + path: /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 +- lineinfile: " + path: /etc/sudoers state: present regexp: '^%wheel\s' line: '%wheel ALL=(ALL) NOPASSWD: ALL' # Yaml requires escaping backslashes in double quotes but not in single quotes - lineinfile: - dest: /opt/jboss-as/bin/standalone.conf - regexp: "^(.*)Xms(\\d+)m(.*)$" + path: /opt/jboss-as/bin/standalone.conf + regexp: '^(.*)Xms(\\d+)m(.*)$' line: '\1Xms${xms}m\3' backrefs: yes # Validate the sudoers file before saving - lineinfile: - dest: /etc/sudoers + path: /etc/sudoers state: present regexp: '^%ADMIN ALL=' line: '%ADMIN ALL=(ALL) NOPASSWD: ALL' @@ -412,7 +416,7 @@ def absent(module, dest, regexp, line, backup): def main(): module = AnsibleModule( argument_spec=dict( - dest=dict(required=True, aliases=['name', 'destfile'], type='path'), + path=dict(required=True, aliases=['dest', 'destfile', 'name'], type='path'), state=dict(default='present', choices=['absent', 'present']), regexp=dict(default=None), line=dict(aliases=['value']), @@ -432,11 +436,11 @@ def main(): create = params['create'] backup = params['backup'] backrefs = params['backrefs'] - dest = params['dest'] + path = params['path'] - b_dest = to_bytes(dest, errors='surrogate_or_strict') - if os.path.isdir(b_dest): - module.fail_json(rc=256, msg='Destination %s is a directory !' % dest) + b_path = to_bytes(path, errors='surrogate_or_strict') + if os.path.isdir(b_path): + module.fail_json(rc=256, msg='Path %s is a directory !' % path) if params['state'] == 'present': if backrefs and params['regexp'] is None: @@ -453,13 +457,13 @@ def main(): line = params['line'] - present(module, dest, params['regexp'], line, + present(module, path, 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) + absent(module, path, params['regexp'], params.get('line', None), backup) if __name__ == '__main__': main() diff --git a/lib/ansible/modules/files/replace.py b/lib/ansible/modules/files/replace.py index d0f6dfecd1..7e8a99139a 100644 --- a/lib/ansible/modules/files/replace.py +++ b/lib/ansible/modules/files/replace.py @@ -43,11 +43,12 @@ description: same pattern would never match any replacements made. version_added: "1.6" options: - dest: + path: required: true - aliases: [ name, destfile ] + aliases: [ dest, destfile, name ] description: - The file to modify. + - Before 2.3 this option was only usable as I(dest), I(destfile) and I(name). regexp: required: true description: @@ -80,30 +81,38 @@ options: version_added: "1.9" description: - 'This flag indicates that filesystem links, if they exist, should be followed.' +notes: + - As of Ansible 2.3, the I(dest) option has been changed to I(path) as default, but I(dest) still works as well. """ EXAMPLES = r""" +# Before 2.3, option 'dest', 'destfile' or 'name' was used instead of 'path' - replace: - dest: /etc/hosts + path: /etc/hosts regexp: '(\s+)old\.host\.name(\s+.*)?$' replace: '\1new.host.name\2' backup: yes - replace: - dest: /home/jdoe/.ssh/known_hosts + path: /home/jdoe/.ssh/known_hosts regexp: '^old\.host\.name[^\n]*\n' owner: jdoe group: jdoe mode: 0644 - replace: - dest: /etc/apache/ports + path: /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): +import os + +# import module snippets +from ansible.module_utils.basic import AnsibleModule + +def write_changes(module, contents, path): tmpfd, tmpfile = tempfile.mkstemp() f = os.fdopen(tmpfd,'wb') @@ -121,7 +130,7 @@ def write_changes(module,contents,dest): module.fail_json(msg='failed to validate: ' 'rc:%s error:%s' % (rc,err)) if valid: - module.atomic_move(tmpfile, dest, unsafe_writes=module.params['unsafe_writes']) + module.atomic_move(tmpfile, path, unsafe_writes=module.params['unsafe_writes']) def check_file_attrs(module, changed, message): @@ -138,7 +147,7 @@ def check_file_attrs(module, changed, message): def main(): module = AnsibleModule( argument_spec=dict( - dest=dict(required=True, aliases=['name', 'destfile']), + path=dict(required=True, aliases=['dest', 'destfile', 'name'], type='path'), regexp=dict(required=True), replace=dict(default='', type='str'), backup=dict(default=False, type='bool'), @@ -149,16 +158,16 @@ def main(): ) params = module.params - dest = os.path.expanduser(params['dest']) + path = os.path.expanduser(params['path']) res_args = dict() - if os.path.isdir(dest): - module.fail_json(rc=256, msg='Destination %s is a directory !' % dest) + if os.path.isdir(path): + module.fail_json(rc=256, msg='Path %s is a directory !' % path) - if not os.path.exists(dest): - module.fail_json(rc=257, msg='Destination %s does not exist !' % dest) + if not os.path.exists(path): + module.fail_json(rc=257, msg='Path %s does not exist !' % path) else: - f = open(dest, 'rb') + f = open(path, 'rb') contents = to_text(f.read(), errors='surrogate_or_strict') f.close() @@ -170,9 +179,9 @@ def main(): changed = True if module._diff: res_args['diff'] = { - 'before_header': dest, + 'before_header': path, 'before': contents, - 'after_header': dest, + 'after_header': path, 'after': result[0], } else: @@ -180,17 +189,14 @@ def main(): changed = False if changed and not module.check_mode: - if params['backup'] and os.path.exists(dest): - res_args['backup_file'] = module.backup_local(dest) - if params['follow'] and os.path.islink(dest): - dest = os.path.realpath(dest) - write_changes(module, result[0], dest) + if params['backup'] and os.path.exists(path): + res_args['backup_file'] = module.backup_local(path) + if params['follow'] and os.path.islink(path): + path = os.path.realpath(path) + write_changes(module, result[0], path) res_args['msg'], res_args['changed'] = check_file_attrs(module, changed, msg) module.exit_json(**res_args) -# this is magic, see lib/ansible/module_common.py -from ansible.module_utils.basic import * - if __name__ == '__main__': main() diff --git a/lib/ansible/modules/files/xattr.py b/lib/ansible/modules/files/xattr.py index 0ae74efbaa..5179dd038d 100644 --- a/lib/ansible/modules/files/xattr.py +++ b/lib/ansible/modules/files/xattr.py @@ -27,12 +27,13 @@ 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: + path: required: true default: None - aliases: ['path'] + aliases: ['name'] description: - - The full path of the file/object to get the facts of + - The full path of the file/object to get the facts of. + - Before 2.3 this option was only usable as I(name). key: required: false default: None @@ -61,6 +62,8 @@ options: description: - if yes, dereferences symlinks and sets/gets attributes on symlink target, otherwise acts on symlink itself. +notes: + - As of Ansible 2.3, the I(name) option has been changed to I(path) as default, but I(name) still works as well. author: "Brian Coca (@bcoca)" ''' @@ -68,7 +71,7 @@ author: "Brian Coca (@bcoca)" EXAMPLES = ''' # Obtain the extended attributes of /etc/foo.conf - xattr: - name: /etc/foo.conf + path: /etc/foo.conf # Sets the key 'foo' to value 'bar' - xattr: @@ -78,7 +81,7 @@ EXAMPLES = ''' # Removes the key 'foo' - xattr: - name: /etc/foo.conf + path: /etc/foo.conf key: user.foo state: absent ''' @@ -87,6 +90,10 @@ import operator import re import os +# import module snippets +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.pycompat24 import get_exception + def get_xattr_keys(module,path,follow): cmd = [ module.get_bin_path('getfattr', True) ] # prevents warning and not sure why it's not default @@ -156,7 +163,7 @@ def _run_xattr(module,cmd,check_rc=True): def main(): module = AnsibleModule( argument_spec = dict( - name = dict(required=True, aliases=['path'], type='path'), + path = dict(required=True, aliases=['name'], type='path'), key = dict(required=False, default=None, type='str'), value = dict(required=False, default=None, type='str'), state = dict(required=False, default='read', choices=[ 'read', 'present', 'all', 'keys', 'absent' ], type='str'), @@ -164,7 +171,7 @@ def main(): ), supports_check_mode=True, ) - path = module.params.get('name') + path = module.params.get('path') key = module.params.get('key') value = module.params.get('value') state = module.params.get('state') @@ -214,8 +221,5 @@ def main(): module.exit_json(changed=changed, msg=msg, xattr=res) -# import module snippets -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.pycompat24 import get_exception if __name__ == '__main__': main() diff --git a/lib/ansible/modules/system/mount.py b/lib/ansible/modules/system/mount.py index b8fad7747b..14cc4fc809 100644 --- a/lib/ansible/modules/system/mount.py +++ b/lib/ansible/modules/system/mount.py @@ -20,16 +20,6 @@ # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . - -from ansible.module_utils._text import to_native -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.basic import get_platform -from ansible.module_utils.ismount import ismount -from ansible.module_utils.pycompat24 import get_exception -from ansible.module_utils.six import iteritems -import os - - ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'core', 'version': '1.0'} @@ -45,13 +35,15 @@ author: - Seth Vidal version_added: "0.6" options: - name: + path: description: - - Path to the mount point (e.g. C(/mnt/files)) + - Path to the mount point (e.g. C(/mnt/files)). + - Before 2.3 this option was only usable as I(dest), I(destfile) and I(name). required: true + aliases: [ name ] src: description: - - Device to be mounted on I(name). Required when I(state) set to + - Device to be mounted on I(path). Required when I(state) set to C(present) or C(mounted). required: false default: null @@ -109,12 +101,15 @@ options: required: false default: yes choices: ["yes", "no"] +notes: + - As of Ansible 2.3, the I(name) option has been changed to I(path) as default, but I(name) still works as well. ''' EXAMPLES = ''' +# Before 2.3, option 'name' was used instead of 'path' - name: Mount DVD read-only mount: - name: /mnt/dvd + path: /mnt/dvd src: /dev/sr0 fstype: iso9660 opts: ro @@ -122,23 +117,31 @@ EXAMPLES = ''' - name: Mount up device by label mount: - name: /srv/disk + path: /srv/disk src: LABEL=SOME_LABEL fstype: ext4 state: present - name: Mount up device by UUID mount: - name: /home + path: /home src: UUID=b3e48f45-f933-4c8e-a700-22a159ec9077 fstype: xfs opts: noatime state: present ''' +import os -def write_fstab(lines, dest): - fs_w = open(dest, 'w') +# import module snippets +from ansible.module_utils._text import to_native +from ansible.module_utils.basic import AnsibleModule, get_platform +from ansible.module_utils.ismount import ismount +from ansible.module_utils.pycompat24 import get_exception +from ansible.module_utils.six import iteritems + +def write_fstab(lines, path): + fs_w = open(path, 'w') for l in lines: fs_w.write(l) @@ -352,11 +355,11 @@ def mount(module, args): return rc, out+err -def umount(module, dest): +def umount(module, path): """Unmount a path.""" umount_bin = module.get_bin_path('umount', required=True) - cmd = [umount_bin, dest] + cmd = [umount_bin, path] rc, out, err = module.run_command(cmd) @@ -584,7 +587,7 @@ def main(): dump=dict(), fstab=dict(default=None), fstype=dict(), - name=dict(required=True, type='path'), + path=dict(required=True, aliases=['name'], type='path'), opts=dict(), passno=dict(type='str'), src=dict(type='path'), @@ -608,7 +611,7 @@ def main(): # explicitly specified it in mount() and remount() if get_platform().lower() == 'sunos': args = dict( - name=module.params['name'], + name=module.params['path'], opts='-', passno='-', fstab=module.params['fstab'], @@ -618,7 +621,7 @@ def main(): args['fstab'] = '/etc/vfstab' else: args = dict( - name=module.params['name'], + name=module.params['path'], opts='defaults', dump='0', passno='0', @@ -667,7 +670,7 @@ def main(): # changed in fstab then remount it. state = module.params['state'] - name = module.params['name'] + name = module.params['path'] if state == 'absent': name, changed = unset_mount(module, args) @@ -735,6 +738,5 @@ def main(): module.exit_json(changed=changed, **args) - if __name__ == '__main__': main() diff --git a/lib/ansible/modules/windows/win_lineinfile.ps1 b/lib/ansible/modules/windows/win_lineinfile.ps1 index 31b5b2f9d6..8a41790810 100644 --- a/lib/ansible/modules/windows/win_lineinfile.ps1 +++ b/lib/ansible/modules/windows/win_lineinfile.ps1 @@ -25,7 +25,7 @@ $params = Parse-Args $args; # Initialize defaults for input parameters. -$dest= Get-Attr $params "dest" $FALSE; +$path= Get-Attr $params "path" $FALSE; $regexp = Get-Attr $params "regexp" $FALSE; $state = Get-Attr $params "state" "present"; $line = Get-Attr $params "line" $FALSE; @@ -39,32 +39,34 @@ $encoding = Get-Attr $params "encoding" "auto"; $newline = Get-Attr $params "newline" "windows"; -# Parse dest / name /destfile param aliases for compatibility with lineinfile +# Parse path / dest / destfile / name param aliases for compatibility with lineinfile # and fail if at least one spelling of the parameter is not provided. -$dest = Get-Attr $params "dest" $FALSE; -If ($dest -eq $FALSE) { - $dest = Get-Attr $params "name" $FALSE; - If ($dest -eq $FALSE) { - $dest = Get-Attr $params "destfile" $FALSE; - If ($dest -eq $FALSE) { - Fail-Json (New-Object psobject) "missing required argument: dest"; +If ($path -eq $FALSE) { + $path = Get-Attr $params "dest" $FALSE; + If ($path -eq $FALSE) { + $path = Get-Attr $params "destfile" $FALSE; + If ($path -eq $FALSE) { + $path = Get-Attr $params "name" $FALSE; + If ($path -eq $FALSE) { + Fail-Json (New-Object psobject) "missing required argument: path"; + } } } } -# Fail if the destination is not a file +# Fail if the path is not a file -If (Test-Path $dest -pathType container) { - Fail-Json (New-Object psobject) "destination is a directory"; +If (Test-Path $path -pathType container) { + Fail-Json (New-Object psobject) "Path $path is a directory"; } # Write lines to a file using the specified line separator and encoding, # performing validation if a validation command was specified. -function WriteLines($outlines, $dest, $linesep, $encodingobj, $validate) { +function WriteLines($outlines, $path, $linesep, $encodingobj, $validate) { $temppath = [System.IO.Path]::GetTempFileName(); $joined = $outlines -join $linesep; [System.IO.File]::WriteAllText($temppath, $joined, $encodingobj); @@ -94,9 +96,9 @@ function WriteLines($outlines, $dest, $linesep, $encodingobj, $validate) { } - # Commit changes to the destination file - $cleandest = $dest.Replace("/", "\"); - Copy-Item $temppath $cleandest -force; + # Commit changes to the path + $cleanpath = $path.Replace("/", "\"); + Copy-Item $temppath $cleanpath -force; Remove-Item $temppath -force; } @@ -113,24 +115,24 @@ function BackupFile($path) { # Implement the functionality for state == 'present' -function Present($dest, $regexp, $line, $insertafter, $insertbefore, $create, $backup, $backrefs, $validate, $encodingobj, $linesep) { +function Present($path, $regexp, $line, $insertafter, $insertbefore, $create, $backup, $backrefs, $validate, $encodingobj, $linesep) { - # Note that we have to clean up the dest path because ansible wants to treat / and \ as + # Note that we have to clean up the path because ansible wants to treat / and \ as # interchangeable in windows pathnames, but .NET framework internals do not support that. - $cleandest = $dest.Replace("/", "\"); + $cleanpath = $path.Replace("/", "\"); - # Check if destination exists. If it does not exist, either create it if create == "yes" + # Check if path exists. If it does not exist, either create it if create == "yes" # was specified or fail with a reasonable error message. - If (!(Test-Path $dest)) { + If (!(Test-Path $path)) { If ($create -eq "no") { - Fail-Json (New-Object psobject) "Destination $dest does not exist !"; + Fail-Json (New-Object psobject) "Path $path does not exist !"; } # Create new empty file, using the specified encoding to write correct BOM - [System.IO.File]::WriteAllLines($cleandest, "", $encodingobj); + [System.IO.File]::WriteAllLines($cleanpath, "", $encodingobj); } # Read the dest file lines using the indicated encoding into a mutable ArrayList. - $content = [System.IO.File]::ReadAllLines($cleandest, $encodingobj); + $content = [System.IO.File]::ReadAllLines($cleanpath, $encodingobj); If ($content -eq $null) { $lines = New-Object System.Collections.ArrayList; } @@ -225,15 +227,15 @@ function Present($dest, $regexp, $line, $insertafter, $insertbefore, $create, $b } # Write backup file if backup == "yes" - $backupdest = ""; + $backuppath = ""; If ($changed -eq $TRUE -and $backup -eq "yes") { - $backupdest = BackupFile $dest; + $backuppath = BackupFile $path; } - # Write changes to the destination file if changes were made + # Write changes to the path if changes were made If ($changed) { - WriteLines $lines $dest $linesep $encodingobj $validate; + WriteLines $lines $path $linesep $encodingobj $validate; } $encodingstr = $encodingobj.WebName; @@ -242,7 +244,7 @@ function Present($dest, $regexp, $line, $insertafter, $insertbefore, $create, $b $result = New-Object psobject @{ changed = $changed msg = $msg - backup = $backupdest + backup = $backuppath encoding = $encodingstr } @@ -252,19 +254,19 @@ function Present($dest, $regexp, $line, $insertafter, $insertbefore, $create, $b # Implement the functionality for state == 'absent' -function Absent($dest, $regexp, $line, $backup, $validate, $encodingobj, $linesep) { +function Absent($path, $regexp, $line, $backup, $validate, $encodingobj, $linesep) { - # Check if destination exists. If it does not exist, fail with a reasonable error message. - If (!(Test-Path $dest)) { - Fail-Json (New-Object psobject) "Destination $dest does not exist !"; + # Check if path exists. If it does not exist, fail with a reasonable error message. + If (!(Test-Path $path)) { + Fail-Json (New-Object psobject) "Path $path does not exist !"; } # Read the dest file lines using the indicated encoding into a mutable ArrayList. Note - # that we have to clean up the dest path because ansible wants to treat / and \ as + # that we have to clean up the path because ansible wants to treat / and \ as # interchangeable in windows pathnames, but .NET framework internals do not support that. - $cleandest = $dest.Replace("/", "\"); - $content = [System.IO.File]::ReadAllLines($cleandest, $encodingobj); + $cleanpath = $path.Replace("/", "\"); + $content = [System.IO.File]::ReadAllLines($cleanpath, $encodingobj); If ($content -eq $null) { $lines = New-Object System.Collections.ArrayList; } @@ -303,15 +305,15 @@ function Absent($dest, $regexp, $line, $backup, $validate, $encodingobj, $linese } # Write backup file if backup == "yes" - $backupdest = ""; + $backuppath = ""; If ($changed -eq $TRUE -and $backup -eq "yes") { - $backupdest = BackupFile $dest; + $backuppath = BackupFile $path; } - # Write changes to the destination file if changes were made + # Write changes to the path if changes were made If ($changed) { - WriteLines $left $dest $linesep $encodingobj $validate; + WriteLines $left $path $linesep $encodingobj $validate; } # Return result information @@ -322,7 +324,7 @@ function Absent($dest, $regexp, $line, $backup, $validate, $encodingobj, $linese $result = New-Object psobject @{ changed = $changed msg = $msg - backup = $backupdest + backup = $backuppath found = $fcount encoding = $encodingstr } @@ -362,7 +364,7 @@ If ($encoding -ne "auto") { # Otherwise see if we can determine the current encoding of the target file. # If the file doesn't exist yet (create == 'yes') we use the default or # explicitly specified encoding set above. -Elseif (Test-Path $dest) { +Elseif (Test-Path $path) { # Get a sorted list of encodings with preambles, longest first @@ -381,7 +383,7 @@ Elseif (Test-Path $dest) { # Get the first N bytes from the file, where N is the max preamble length we saw - [Byte[]]$bom = Get-Content -Encoding Byte -ReadCount $max_preamble_len -TotalCount $max_preamble_len -Path $dest; + [Byte[]]$bom = Get-Content -Encoding Byte -ReadCount $max_preamble_len -TotalCount $max_preamble_len -Path $path; # Iterate through the sorted encodings, looking for a full match. @@ -426,7 +428,7 @@ If ($state -eq "present") { $insertafter = "EOF"; } - Present $dest $regexp $line $insertafter $insertbefore $create $backup $backrefs $validate $encodingobj $linesep; + Present $path $regexp $line $insertafter $insertbefore $create $backup $backrefs $validate $encodingobj $linesep; } Else { @@ -435,22 +437,5 @@ Else { Fail-Json (New-Object psobject) "one of line= or regexp= is required with state=absent"; } - Absent $dest $regexp $line $backup $validate $encodingobj $linesep; + Absent $path $regexp $line $backup $validate $encodingobj $linesep; } - - - - - - - - - - - - - - - - - diff --git a/lib/ansible/modules/windows/win_lineinfile.py b/lib/ansible/modules/windows/win_lineinfile.py index df250d6d41..d2b411c949 100644 --- a/lib/ansible/modules/windows/win_lineinfile.py +++ b/lib/ansible/modules/windows/win_lineinfile.py @@ -30,12 +30,13 @@ description: - This is primarily useful when you want to change a single line in a file only. version_added: "2.0" options: - dest: + path: required: true - aliases: [ name, destfile ] + aliases: [ dest, destfile, name ] description: - The path of the file to modify. - Note that the Windows path delimiter C(\) must be escaped as C(\\) when the line is double quoted. + - Before 2.3 this option was only usable as I(dest), I(destfile) and I(name). regexp: required: false description: @@ -101,46 +102,49 @@ options: - "Specifies the line separator style to use for the modified file. This defaults to the windows line separator (C(\r\n)). Note that the indicated line separator will be used for file output regardless of the original line separator that appears in the input file." choices: [ "windows", "unix" ] default: "windows" +notes: + - As of Ansible 2.3, the I(dest) option has been changed to I(path) as default, but I(dest) still works as well. """ EXAMPLES = r""" +# Before 2.3, option 'dest', 'destfile' or 'name' was used instead of 'path' - win_lineinfile: - dest: C:\temp\example.conf + path: C:\temp\example.conf regexp: '^name=' line: 'name=JohnDoe' - win_lineinfile: - dest: C:\temp\example.conf + path: C:\temp\example.conf regexp: '^name=' state: absent - win_lineinfile: - dest: C:\temp\example.conf + path: C:\temp\example.conf regexp: '^127\.0\.0\.1' line: '127.0.0.1 localhost' - win_lineinfile: - dest: C:\temp\httpd.conf + path: C:\temp\httpd.conf regexp: '^Listen ' insertafter: '^#Listen ' line: Listen 8080 - win_lineinfile: - dest: C:\temp\services + path: C:\temp\services regexp: '^# port for http' insertbefore: '^www.*80/tcp' line: '# port for http by default' # Create file if it doesn't exist with a specific encoding - win_lineinfile: - dest: C:\temp\utf16.txt + path: C:\temp\utf16.txt create: yes encoding: utf-16 line: This is a utf-16 encoded file # Add a line to a file and ensure the resulting file uses unix line separators - win_lineinfile: - dest: C:\temp\testfile.txt + path: C:\temp\testfile.txt line: Line added to file newline: unix """