diff --git a/library/files/lineinfile b/library/files/lineinfile index b518158cdf..783c3d2911 100644 --- a/library/files/lineinfile +++ b/library/files/lineinfile @@ -107,6 +107,13 @@ options: 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 + version_added: "1.4" others: description: - All arguments accepted by the M(file) module also work here. @@ -128,6 +135,9 @@ EXAMPLES = r""" - 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): @@ -137,7 +147,16 @@ def write_changes(module,lines,dest): f.writelines(lines) f.close() - module.atomic_move(tmpfile, dest) + validate = module.params.get('validate', None) + valid = not validate + if 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): @@ -167,8 +186,6 @@ def present(module, dest, regexp, line, insertafter, insertbefore, create, lines = f.readlines() f.close() - msg = "" - mre = re.compile(regexp) if insertafter not in (None, 'BOF', 'EOF'): @@ -289,6 +306,7 @@ def main(): 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, diff --git a/test/TestRunner.py b/test/TestRunner.py index 193b560d84..f991d02bd3 100644 --- a/test/TestRunner.py +++ b/test/TestRunner.py @@ -460,6 +460,32 @@ class TestRunner(unittest.TestCase): idx = artifact.index('communication. Typically it is depicted as a lunch-box sized object with some') assert artifact[idx - 1] == testline + # Testing validate + testline = 'Tenth: Testing with validate' + testcase = ('lineinfile', [ + "dest=%s" % sample, + "regexp='^Tenth: '", + "line='%s'" % testline, + "validate='grep -q Tenth %s'", + ]) + result = self._run(*testcase) + assert result['changed'], "File wasn't changed when it should have been" + assert result['msg'] == 'line added', "msg was incorrect" + artifact = [ x.strip() for x in open(sample) ] + assert artifact[-1] == testline + + + # Testing validate + testline = '#11: Testing with validate' + testcase = ('lineinfile', [ + "dest=%s" % sample, + "regexp='^#11: '", + "line='%s'" % testline, + "validate='grep -q #12# %s'", + ]) + result = self._run(*testcase) + assert result['failed'] + # cleanup os.unlink(sample)