Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add vault_password_file param to PlaybookRunner #129

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions rrmngmnt/playbook_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def _generate_default_inventory(self):
def run(
self, playbook, extra_vars=None, vars_files=None, inventory=None,
verbose_level=1, run_in_check_mode=False, ssh_common_args=None,
upload_playbook=True
upload_playbook=True, vault_password_file=None,
):
"""
Run Ansible playbook on host
Expand All @@ -121,7 +121,8 @@ def run(
vars_files (list): List of additional variable files to be included
using -e@ parameter. If one variable is specified both in
extra_vars and in one of the vars_files, the one in vars_files
takes precedence.
takes precedence. Provide local paths to vars file(s), they
will be uploaded to a remote host automatically.
inventory (str): Path to an inventory file (on your machine) to be
used for playbook execution. If none is provided, default
inventory including only localhost will be generated and used
Expand All @@ -134,8 +135,13 @@ def run(
replace) the list of default options that Ansible uses when
calling ssh/sftp/scp. Example: ["-o StrictHostKeyChecking=no",
"-o UserKnownHostsFile=/dev/null"]
upload_playbook (bool): If the playbook is going to be uploaded
from the local machine (True - Default) or not (False)
upload_playbook (bool): Whether the playbook is going to be
automatically uploaded from the local machine to a remote host
(True - Default) or not (False).
vault_password_file (str): Local path to a vault password file.
It will be automatically uploaded to a remote host,
same as vars_files. This is required if any of the vars_files
are vault-protected.

Returns:
tuple: tuple of (rc, out, err)
Expand All @@ -158,6 +164,13 @@ def run(
for f in vars_files:
self.cmd.append("-e@{}".format(self._upload_file(f)))

if vault_password_file:
self.cmd.append(
"--vault-password-file={}".format(
self._upload_file(vault_password_file)
)
)

Copy link
Member

@lukas-bednar lukas-bednar May 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on line 188, I guess that you will have to upload that key file to host server, in case upload_playbook=True

EDIT:

Actually other way around. You have to pass local path to key in case upload_paybook=False.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you always have to pass local paths to both vault_password_file and to vars_files. No matter the value of upload_playbook. Let me update the docstring so this is clearer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.upload_file returns path on remote host. and in case you pass upload_playbook=False you should pass "--vault-password-file={}".format(vault_password_file) , no?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you do have a point, but exactly the same also goes for vars_files. When I originally wrote this class and method, I never intended for user to upload any of those files manually. The parameters upload_playbook was implemented by @santos1709 and back then it was agreed that we wouldn't accommodate vars_files to it. However, it we want vars_files and vault_password_file to react on the value of upload_playbook, I think this requires bigger and more careful change. If that's the case, I suggest tracking it in a new issue/ticket.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, please open an issue. and we will merge this one.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tracked in #130 . I'll also create a ticket in our Jira board

self.cmd.append("-i")
if inventory:
self.cmd.append(self._upload_file(inventory))
Expand Down
57 changes: 57 additions & 0 deletions tests/test_playbook_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class PlaybookRunnerBase(object):
playbook_content = ''
vars_file_name = 'my_vars.yml'
vars_file_content = ''
vault_password_file_name = 'key.txt'
vault_password_file_content = ''
inventory_name = 'my_inventory'
inventory_content = ''
ssh_no_strict_host_key_checking = "-o StrictHostKeyChecking=no"
Expand All @@ -36,6 +38,9 @@ class PlaybookRunnerBase(object):
'[ -d {tmp_dir}/{vars_file} ]'.format(
tmp_dir=tmp_dir, vars_file=vars_file_name
): failure,
'[ -d {tmp_dir}/{vault_password_file} ]'.format(
tmp_dir=tmp_dir, vault_password_file=vault_password_file_name,
): failure,
'[ -d {tmp_dir}/{inventory} ]'.format(
tmp_dir=tmp_dir, inventory=inventory_name
): failure,
Expand Down Expand Up @@ -65,6 +70,17 @@ class PlaybookRunnerBase(object):
inventory=PlaybookRunner.default_inventory_name,
playbook=playbook_name
): success,
# Vault password file has been provided
'{bin} -e@{tmp_dir}/{vars_file} '
'--vault-password-file={tmp_dir}/{vault_password_file} '
'-i {tmp_dir}/{inventory} -v {tmp_dir}/{playbook}'.format(
bin=PlaybookRunner.binary,
vars_file=vars_file_name,
vault_password_file=vault_password_file_name,
tmp_dir=tmp_dir,
inventory=PlaybookRunner.default_inventory_name,
playbook=playbook_name
): success,
# Custom inventory has been provided
'{bin} -i {tmp_dir}/{inventory} -v {tmp_dir}/{playbook}'.format(
bin=PlaybookRunner.binary,
Expand Down Expand Up @@ -236,6 +252,47 @@ def test_vars_file(self, playbook_runner, fake_playbook, fake_vars_file):
)


class TestVaultPasswordFile(PlaybookRunnerBase):

files = {}

@pytest.fixture()
def fake_protected_file(self, tmpdir):
fpf = tmpdir.join(self.vars_file_name)
fpf.write(self.vars_file_content)
return str(fpf)

@pytest.fixture()
def fake_vault_password_file(self, tmpdir):
fvpf = tmpdir.join(self.vault_password_file_name)
fvpf.write(self.vault_password_file_content)
return str(fvpf)

def test_vault_password_file(
self, playbook_runner, fake_playbook,
fake_protected_file, fake_vault_password_file
):
"""
User has provided YAML file with variables protected by ansible-vault.
They also provided vault password file unlocking vars file.
"""
rc, _, _ = playbook_runner.run(
playbook=fake_playbook,
vars_files=[fake_protected_file],
vault_password_file=fake_vault_password_file,
)
assert not rc
assert self.check_files_on_host(
[
os.path.join(
self.tmp_dir, PlaybookRunner.default_inventory_name
),
os.path.join(self.tmp_dir, self.vars_file_name),
os.path.join(self.tmp_dir, self.vault_password_file_name)
]
)


class TestInventory(PlaybookRunnerBase):

files = {}
Expand Down