From 2dd24ea806b26a58a546889fb922d598f4811c25 Mon Sep 17 00:00:00 2001 From: Adam Bullmer Date: Sun, 11 Mar 2018 20:47:12 -0500 Subject: [PATCH] Allowing for global, OS, and per-project ansible path specifications Fixes #5 --- AnsibleVault.sublime-settings | 3 + README.md | 16 +++-- commands.py | 110 +++++++++++++++++++--------------- 3 files changed, 76 insertions(+), 53 deletions(-) diff --git a/AnsibleVault.sublime-settings b/AnsibleVault.sublime-settings index ce47521..f399c93 100644 --- a/AnsibleVault.sublime-settings +++ b/AnsibleVault.sublime-settings @@ -25,4 +25,7 @@ * does. */ "password": "", + + "debug": false, + "ansible_path": "", } diff --git a/README.md b/README.md index 40fb709..2160646 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,12 @@ instead. ## Configuration The following options are available: -| Option | Description | -|-----------------|-------------| -| `password` | Plain text ansible vault password. | -| `password_file` | Absolute path to your ansible vault [password file](http://docs.ansible.com/ansible/playbooks_vault.html#running-a-playbook-with-vault) | +| Setting | Default | Description | +|-----------------|---------|-------------| +| `password` | `''` | Plain text ansible vault password. | +| `password_file` | `''` | Absolute path to your ansible vault [password file](http://docs.ansible.com/ansible/playbooks_vault.html#running-a-playbook-with-vault) | +| `debug` | `false` | true/false flag for extra logging into the sublime text console. | +| `ansible_path` | `''` | Path override if it is desired to not use a system version of ansible-vault. Use the path to the binary directory with a trailing slash. This is useful for using the binary out of a virtualenv. | If none of the password options are used, then you will be prompted for your password on each vault action. @@ -45,8 +47,10 @@ You can override all settings with the use of the configuration key inside of yo //... Folder List here ], "AnsibleVault": { - "password": "plain text password", // OR - "password_file": "/absolute/path/to/password_file" + "password_file": "/absolute/path/to/password_file", // OR + "password": "plain text password", // Not recommended + "debug": true, + "ansible_path": "/usr/local/bin/", } } ``` diff --git a/commands.py b/commands.py index 5990bf5..4e85352 100644 --- a/commands.py +++ b/commands.py @@ -1,18 +1,15 @@ from functools import partial -import logging from subprocess import Popen, PIPE import sublime import sublime_plugin -log = logging.getLogger(__name__) +ANSIBLE_COMMAND_TEMPLATE = '{ansible_path}ansible-vault {command} {extra_flags} {vault_password} "{vault_file}"' +GETPASS_WARNING = "Warning: Password input may be echoed.\nVault password:" -ANSIBLE_COMMAND_TEMPLATE = 'ansible-vault {command} {extra_flags} {vault_password} "{vault_file}"' -GETPASS_WARNING = "Warning: Password input may be echoed.\nVault password: " - -class AnsibleVaultBase: +class AnsibleVaultBaseCommand(sublime_plugin.TextCommand): open_new_tab = False command = None password = None @@ -31,6 +28,14 @@ def password(self): def password_file(self): return self.get_setting('password_file') + @property + def ansible_path(self): + return self.get_setting('ansible_path', '') + + def run(self, edit): + self.vault_file_path = self.view.file_name() + self.ansible_vault() + def debug_log(self, message): if self.debug: print('ANSIBLE VAULT: "%s"' % message) @@ -57,8 +62,8 @@ def get_setting(self, key, default=None): return settings.get(key, default) - def prompt_vault_password(self, edit, vault_file_path): - bound_vault_command = partial(self.run_vault_command, edit, vault_file_path) + def prompt_vault_password(self): + bound_vault_command = partial(self.run_vault_command) self.view.window().show_input_panel('Vault Password', '', bound_vault_command, self.on_change, self.on_cancel) def on_change(self, password): @@ -67,43 +72,50 @@ def on_change(self, password): def on_cancel(self): pass - def ansible_vault(self, edit, vault_file_path): + def ansible_vault(self): # Use a password file is one is present - if self.password_file != '': - return self.run_vault_command(edit, vault_file_path, self.password_file, password_from_file=True) - - # Use a password if one is present - if self.password != '': - return self.run_vault_command(edit, vault_file_path, self.password) + if self.password_file == '' and self.password == '': + # No configured password, fallback to a prompt + return self.prompt_vault_password() - # No configured password, fallback to a prompt - self.prompt_vault_password(edit, vault_file_path) + return self.run_vault_command() - def run_vault_command(self, edit, vault_file_path, password, password_from_file=False): - vault_password_flag = '--vault-password-file "%s"' % password + def run_vault_command(self, password=None): + vault_password_flag = '--ask-vault-pass' password_input = None - if password_from_file is False: - vault_password_flag = '--ask-vault-pass' + if self.password_file != '': + vault_password_flag = '--vault-password-file "%s"' % self.password_file + elif self.password != '': + password_input = self.password + else: password_input = password command = ANSIBLE_COMMAND_TEMPLATE.format( + ansible_path=self.ansible_path, vault_password=vault_password_flag, command=self.command, - vault_file=vault_file_path, + vault_file=self.vault_file_path, extra_flags=self.extra_flags, ) + output = self.exec_command(command, password_input) + if output is False: + return + + self.view.run_command('ansible_vault_output', { + 'output': output, + 'title': self.vault_file_path, + 'new_file': self.open_new_tab, + }) + + def exec_command(self, command, input_=None): with Popen([command], stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, universal_newlines=True) as proc: - output, error = proc.communicate(input=password_input) + output, error = proc.communicate(input='%s\n' % input_) if self.error_handler(error) is True: - return + return False - if self.open_new_tab is True: - self.view.run_command('ansible_vault_output', {'output': output, 'title': vault_file_path}) - else: - region = sublime.Region(0, self.view.size()) - self.view.replace(edit, region, output) + return output def error_handler(self, error): error = error.strip() @@ -116,45 +128,49 @@ def error_handler(self, error): getpass_position = error.find(GETPASS_WARNING) if getpass_position > -1: getpass_position += len(GETPASS_WARNING) + error = error[getpass_position:] - if not error[getpass_position:].strip(): + if not error.strip(): return False - sublime.error_message(error[getpass_position:]) + sublime.error_message(error) return True class AnsibleVaultOutputCommand(sublime_plugin.TextCommand): - def run(self, edit, output=None, title=None): + """Command to output the result of the decryption.""" + + def run(self, edit, output=None, title=None, new_file=False): + if new_file is True: + self.read_only_view(edit, output, title) + else: + self.same_view(edit, output) + + def same_view(self, edit, output): + region = sublime.Region(0, self.view.size()) + self.view.replace(edit, region, output) + + def read_only_view(self, edit, output, title): output_view = self.view.window().new_file() output_view.set_name(title) output_view.insert(edit, 0, output) output_view.set_syntax_file('Packages/YAML/YAML.sublime-syntax') output_view.set_read_only(True) + def error_handler(self): + pass + -class AnsibleVaultViewCommand(AnsibleVaultBase, sublime_plugin.TextCommand): +class AnsibleVaultViewCommand(AnsibleVaultBaseCommand): command = 'view' open_new_tab = True - def run(self, edit): - vault_file = self.view.file_name() - self.ansible_vault(edit, vault_file) - -class AnsibleVaultDecryptCommand(AnsibleVaultBase, sublime_plugin.TextCommand): +class AnsibleVaultDecryptCommand(AnsibleVaultBaseCommand): command = 'decrypt' extra_flags = '--output=-' - def run(self, edit): - vault_file = self.view.file_name() - self.ansible_vault(edit, vault_file) - -class AnsibleVaultEncryptCommand(AnsibleVaultBase, sublime_plugin.TextCommand): +class AnsibleVaultEncryptCommand(AnsibleVaultBaseCommand): command = 'encrypt' extra_flags = '--output=-' - - def run(self, edit): - vault_file = self.view.file_name() - self.ansible_vault(edit, vault_file)