#!/usr/bin/env python # (c) 2014, James Tanner # # 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 . # # ansible-pull is a script that runs ansible in local mode # after checking out a playbooks directory from source repo. There is an # example playbook to bootstrap this script in the examples/ dir which # installs ansible and sets it up to run on cron. #__requires__ = ['ansible'] #import pkg_resources import os import sys import traceback from ansible import utils from ansible import errors from ansible.utils.vault import VaultEditor from optparse import OptionParser #------------------------------------------------------------------------------------- # Utility functions for parsing actions/options #------------------------------------------------------------------------------------- VALID_ACTIONS = ("create", "decrypt", "edit", "encrypt", "rekey", "view") def build_option_parser(action): """ Builds an option parser object based on the action the user wants to execute. """ usage = "usage: %%prog [%s] [--help] [options] file_name" % "|".join(VALID_ACTIONS) epilog = "\nSee '%s --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0]) OptionParser.format_epilog = lambda self, formatter: self.epilog parser = OptionParser(usage=usage, epilog=epilog) if not action: parser.print_help() sys.exit() # options for all actions #parser.add_option('-c', '--cipher', dest='cipher', default="AES256", help="cipher to use") parser.add_option('--debug', dest='debug', action="store_true", help="debug") parser.add_option('--vault-password-file', dest='password_file', help="vault password file") # options specific to actions if action == "create": parser.set_usage("usage: %prog create [options] file_name") elif action == "decrypt": parser.set_usage("usage: %prog decrypt [options] file_name") elif action == "edit": parser.set_usage("usage: %prog edit [options] file_name") elif action == "view": parser.set_usage("usage: %prog view [options] file_name") elif action == "encrypt": parser.set_usage("usage: %prog encrypt [options] file_name") elif action == "rekey": parser.set_usage("usage: %prog rekey [options] file_name") # done, return the parser return parser def get_action(args): """ Get the action the user wants to execute from the sys argv list. """ for i in range(0,len(args)): arg = args[i] if arg in VALID_ACTIONS: del args[i] return arg return None def get_opt(options, k, defval=""): """ Returns an option from an Optparse values instance. """ try: data = getattr(options, k) except: return defval if k == "roles_path": if os.pathsep in data: data = data.split(os.pathsep)[0] return data #------------------------------------------------------------------------------------- # Command functions #------------------------------------------------------------------------------------- def _read_password(filename): f = open(filename, "rb") data = f.read() f.close() data = data.strip() return data def execute_create(args, options, parser): if len(args) > 1: raise errors.AnsibleError("'create' does not accept more than one filename") if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True) else: password = _read_password(options.password_file) cipher = 'AES256' if hasattr(options, 'cipher'): cipher = options.cipher this_editor = VaultEditor(cipher, password, args[0]) this_editor.create_file() def execute_decrypt(args, options, parser): if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True) else: password = _read_password(options.password_file) cipher = 'AES256' if hasattr(options, 'cipher'): cipher = options.cipher for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.decrypt_file() print "Decryption successful" def execute_edit(args, options, parser): if len(args) > 1: raise errors.AnsibleError("edit does not accept more than one filename") if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True) else: password = _read_password(options.password_file) cipher = None for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.edit_file() def execute_view(args, options, parser): if len(args) > 1: raise errors.AnsibleError("view does not accept more than one filename") if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True) else: password = _read_password(options.password_file) cipher = None for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.view_file() def execute_encrypt(args, options, parser): if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True) else: password = _read_password(options.password_file) cipher = 'AES256' if hasattr(options, 'cipher'): cipher = options.cipher for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.encrypt_file() print "Encryption successful" def execute_rekey(args, options, parser): if not options.password_file: password, __ = utils.ask_vault_passwords(ask_vault_pass=True) else: password = _read_password(options.password_file) __, new_password = utils.ask_vault_passwords(ask_vault_pass=False, ask_new_vault_pass=True, confirm_new=True) cipher = None for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.rekey_file(new_password) print "Rekey successful" #------------------------------------------------------------------------------------- # MAIN #------------------------------------------------------------------------------------- def main(): action = get_action(sys.argv) parser = build_option_parser(action) (options, args) = parser.parse_args() if not len(args): raise errors.AnsibleError( "The '%s' command requires a filename as the first argument" % action ) # execute the desired action try: fn = globals()["execute_%s" % action] fn(args, options, parser) except Exception, err: if options.debug: print traceback.format_exc() print "ERROR:",err sys.exit(1) if __name__ == "__main__": main()