Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Add support for ansible options related to ansible-vault (#54)
Browse files Browse the repository at this point in the history
* Added support for ansible options related to ansible-vault

* Ensured that the new options work fine from subfolders
  • Loading branch information
ellmetha authored and Virgil Dupras committed Mar 31, 2017
1 parent b3b7235 commit a66c86a
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 8 deletions.
28 changes: 27 additions & 1 deletion docs/provisioners/ansible.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,32 @@ your containers are provisioned.
Optional options
----------------

*Not yet!*
ask_vault_pass
==============

You can use this option to force the use of the ``--ask-vault-pass`` flag when the
``ansible-playbook`` command is executed during the provisioning workflow. Here is an example:

.. code-block:: yaml
[...]
provisioning:
- type: ansible
playbook: deploy/site.yml
ask_vault_pass: yes
vault_password_file
===================

You can use this option to specify the path toward the vault password file you want to use when the
``ansible-playbook`` command is executed. Here is an example:

.. code-block:: yaml
[...]
provisioning:
- type: ansible
playbook: deploy/site.yml
vault_password_file: secrets/vaultpass
.. _Ansible: https://www.ansible.com/
4 changes: 3 additions & 1 deletion docs/release_notes/v0.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ New features
------------

* Add support for ZSH completion
* Add the possibility to use the `lxdock` command from subfolders
* Add the possibility to use the ``lxdock`` command from subfolders
* Add support for ansible options related to ansible-vault
(``ask_vault_pass``, ``vault_password_file``)
28 changes: 23 additions & 5 deletions lxdock/provisioners/ansible.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import logging
import os
import subprocess
import tempfile

from voluptuous import Required
from voluptuous import IsFile, Required

from ..network import get_ipv4_ip

Expand All @@ -17,7 +16,9 @@ class AnsibleProvisioner(Provisioner):

name = 'ansible'
schema = {
Required('playbook'): str,
Required('playbook'): IsFile(),
'ask_vault_pass': bool,
'vault_password_file': IsFile(),
}

def provision(self):
Expand All @@ -26,8 +27,25 @@ def provision(self):
with tempfile.NamedTemporaryFile() as tmpinv:
tmpinv.write('{} ansible_user=root'.format(ip).encode('ascii'))
tmpinv.flush()
cmd = 'ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i {} {}'.format(
tmpinv.name, os.path.join(self.homedir, self.options['playbook']))
cmd = self._build_ansible_playbook_command(tmpinv.name)
logger.debug(cmd)
p = subprocess.Popen(cmd, shell=True)
p.wait()

def _build_ansible_playbook_command(self, inventory_filename):
cmd_args = ['ANSIBLE_HOST_KEY_CHECKING=False', 'ansible-playbook', ]
cmd_args.extend(['--inventory-file', inventory_filename, ])

# Append the --ask-vault-pass option if applicable.
if self.options.get('ask_vault_pass'):
cmd_args.append('--ask-vault-pass')

# Append the --vault-password-file option if applicable.
vault_password_file = self.options.get('vault_password_file')
if vault_password_file is not None:
cmd_args.extend([
'--vault-password-file', self.homedir_expanded_path(vault_password_file)])

# Append the playbook filepath and return the final command.
cmd_args.append(self.homedir_expanded_path(self.options['playbook']))
return ' '.join(cmd_args)
10 changes: 10 additions & 0 deletions lxdock/provisioners/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
supported by LXDock (eg. Ansible, ...).
"""

import os

from ..utils.metaclass import with_metaclass

__all__ = ['Provisioner', ]
Expand Down Expand Up @@ -84,3 +86,11 @@ def __init__(self, homedir, lxd_container, options):
def provision(self):
""" Performs the provisioning operations using the considered provisioner. """
# This method should be overriden in `Provisioner` subclasses.

##################
# HELPER METHODS #
##################

def homedir_expanded_path(self, relative_path):
""" Expands the considered path with the absolute path of the home homedir. """
return os.path.join(self.homedir, relative_path)
55 changes: 54 additions & 1 deletion tests/unit/provisioners/test_ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,57 @@ def write(self, data):
provisioner = AnsibleProvisioner('./', lxd_container, {'playbook': 'deploy.yml'})
provisioner.provision()
assert mock_popen.call_args[0] == (
'ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -i tmpfile ./deploy.yml', )
'ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook --inventory-file '
'tmpfile ./deploy.yml', )

@unittest.mock.patch('subprocess.Popen')
@unittest.mock.patch('tempfile.NamedTemporaryFile')
def test_can_run_ansible_playbooks_with_the_vault_password_file_option(
self, mock_tempfile, mock_popen):
class MockedTMPFile:
name = 'tmpfile'

def flush(self):
pass

def write(self, data):
pass

mock_tempfile.return_value.__enter__.return_value = MockedTMPFile()
lxd_container = unittest.mock.Mock()
lxd_state = unittest.mock.Mock()
lxd_state.network.__getitem__ = unittest.mock.MagicMock(
return_value={'addresses': [{'family': 'init', 'address': '0.0.0.0', }, ]})
lxd_container.state.return_value = lxd_state
provisioner = AnsibleProvisioner(
'./', lxd_container, {'playbook': 'deploy.yml', 'vault_password_file': '.vpass'})
provisioner.provision()
assert mock_popen.call_args[0] == (
'ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook --inventory-file '
'tmpfile --vault-password-file ./.vpass ./deploy.yml', )

@unittest.mock.patch('subprocess.Popen')
@unittest.mock.patch('tempfile.NamedTemporaryFile')
def test_can_run_ansible_playbooks_with_the_ask_vault_pass_option(
self, mock_tempfile, mock_popen):
class MockedTMPFile:
name = 'tmpfile'

def flush(self):
pass

def write(self, data):
pass

mock_tempfile.return_value.__enter__.return_value = MockedTMPFile()
lxd_container = unittest.mock.Mock()
lxd_state = unittest.mock.Mock()
lxd_state.network.__getitem__ = unittest.mock.MagicMock(
return_value={'addresses': [{'family': 'init', 'address': '0.0.0.0', }, ]})
lxd_container.state.return_value = lxd_state
provisioner = AnsibleProvisioner(
'./', lxd_container, {'playbook': 'deploy.yml', 'ask_vault_pass': True})
provisioner.provision()
assert mock_popen.call_args[0] == (
'ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook --inventory-file '
'tmpfile --ask-vault-pass ./deploy.yml', )

0 comments on commit a66c86a

Please sign in to comment.