From a0422bd534f4b01233b3c9ae8aec56a57a16fe26 Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Tue, 26 Mar 2013 23:12:56 -0400 Subject: [PATCH] Added 'validate' feature to copy and template modules, now you can add a check to force copy to fail if the check fails. had to add entry in file for it to accept as a option even though file itself ignores it. Signed-off-by: Brian Coca --- library/copy | 15 ++++++++++++++- library/file | 3 ++- library/template | 8 ++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/library/copy b/library/copy index 5f3f132a670..d380c16bf92 100644 --- a/library/copy +++ b/library/copy @@ -64,7 +64,12 @@ options: choices: [ "yes", "no" ] default: "yes" aliases: [ "thirsty" ] - others: + validate: + description: + - validation to run before copying into place + required: false + default: "" + version_added: "1.2" others: description: - all arguments accepted by the M(file) module also work here @@ -74,6 +79,8 @@ examples: description: "Example from Ansible Playbooks" - code: "copy: src=/mine/ntp.conf dest=/etc/ntp.conf owner=root group=root mode=644 backup=yes" description: "Copy a new C(ntp.conf) file into place, backing up the original if it differs from the copied version" + - code: "copy: src=/mine/sudoers dest=/etc/sudoers validate='visudo -c %s' + description: "Copy a new C(sudoers) file into place, after passing validation with visudo" author: Michael DeHaan notes: - The "copy" module can't be used to recursively copy directory structures to the target machine. Please see the @@ -91,6 +98,7 @@ def main(): dest = dict(required=True), backup = dict(default=False, type='bool'), force = dict(default=True, aliases=['thirsty'], type='bool'), + validate = dict(required=False, type='str'), ), add_file_common_args=True, ) @@ -100,6 +108,7 @@ def main(): backup = module.params['backup'] force = module.params['force'] original_basename = module.params.get('original_basename',None) + validate = module.params.get('validate',None) if not os.path.exists(src): module.fail_json(msg="Source %s failed to transfer" % (src)) @@ -139,6 +148,10 @@ def main(): # might be an issue with exceeding path length dest_tmp = "%s.%s.%s.tmp" % (dest,os.getpid(),time.time()) shutil.copyfile(src, dest_tmp) + if validate: + (rc,out,err) = module.run_command(validate % dest_tmp) + if rc != 0: + module.fail_json(msg="failed to validate: rc:%s error:%s" % (rc,err)) module.atomic_replace(dest_tmp, dest) except shutil.Error: module.fail_json(msg="failed to copy: %s and %s are the same" % (src, dest)) diff --git a/library/file b/library/file index f4f65e656d3..31719865dbe 100644 --- a/library/file +++ b/library/file @@ -140,7 +140,8 @@ def main(): state = dict(choices=['file','directory','link','absent'], default='file'), path = dict(aliases=['dest', 'name'], required=True), recurse = dict(default='no', type='bool'), - diff_peek = dict(default=None) + diff_peek = dict(default=None), + validate = dict(required=False, default=None), ), add_file_common_args=True, supports_check_mode=True diff --git a/library/template b/library/template index 11fb33bd03c..55eeed3dade 100644 --- a/library/template +++ b/library/template @@ -35,6 +35,12 @@ options: required: false choices: [ "yes", "no" ] default: "no" + validate: + description: + - validation to run before copying into place + required: false + default: "" + version_added: "1.2" others: description: - all arguments accepted by the M(file) module also work here @@ -42,6 +48,8 @@ options: examples: - code: "template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode=0644" description: "Example from Ansible Playbooks" + - code: "action: temlpate src=/mine/sudoers dest=/etc/sudoers validate='visudo -c %s'" + description: "Copy a new C(sudoers) file into place, after passing validation with visudo" notes: - Since Ansible version 0.9, templates are loaded with C(trim_blocks=True). - 'You can override jinja2 settings by adding a special header to template file.