Exemplo n.º 1
0
def test_src_dst_all_files(path, labels, mocker):
    """Ensure file paths are tranformed correctly into dir paths"""
    src_str = os.path.join(resolve_path(path.path), "")
    dst_str = src_str
    expected = generate_volmount_args(src_str=src_str,
                                      dst_str=dst_str,
                                      labels=labels)

    result = []
    src_file = os.path.join(path.path, "", "file.txt")
    dest_file = src_file

    base_config = BaseConfig()
    mocker.patch("os.path.exists", return_value=True)
    mocker.patch("os.path.isdir", return_value=False)
    base_config._update_volume_mount_paths(args_list=result,
                                           src_mount_path=src_file,
                                           dst_mount_path=dest_file,
                                           labels=labels)

    explanation = (
        f"provided: {src_file}:{dest_file}",
        f"got: {result}",
        f"expected {expected}",
    )
    assert result == expected, explanation
    assert all(part.endswith('/')
               for part in result[1].split(':')[0:1]), explanation
Exemplo n.º 2
0
def test_wrap_args_with_ssh_agent_with_auth():
    rc = BaseConfig(private_data_dir='/tmp')
    res = rc.wrap_args_with_ssh_agent(['ansible-playbook', 'main.yaml'],
                                      '/tmp/sshkey', '/tmp/sshauth')
    assert res == [
        'ssh-agent', '-a', '/tmp/sshauth', 'sh', '-c',
        "trap 'rm -f /tmp/sshkey' EXIT && ssh-add /tmp/sshkey && rm -f /tmp/sshkey && ansible-playbook main.yaml"
    ]
Exemplo n.º 3
0
def test_check_not_safe_to_mount_dir(not_safe, mocker):
    """Ensure unsafe directories are not mounted"""
    with pytest.raises(ConfigurationError):
        bc = BaseConfig()
        mocker.patch("os.path.exists", return_value=True)
        bc._update_volume_mount_paths(args_list=[],
                                      src_mount_path=not_safe,
                                      dst_mount_path=None)
Exemplo n.º 4
0
def test_prepare_env_defaults():
    rc = BaseConfig(host_cwd='/tmp/project')
    rc._prepare_env()

    assert rc.idle_timeout is None
    assert rc.job_timeout is None
    assert rc.pexpect_timeout == 5
    assert rc.host_cwd == '/tmp/project'
Exemplo n.º 5
0
def test_wrap_args_with_ssh_agent_defaults(tmp_path):
    rc = BaseConfig(private_data_dir=str(tmp_path))
    res = rc.wrap_args_with_ssh_agent(['ansible-playbook', 'main.yaml'],
                                      f'{tmp_path}/sshkey')
    assert res == [
        'ssh-agent', 'sh', '-c',
        f"trap 'rm -f {tmp_path}/sshkey' EXIT && ssh-add {tmp_path}/sshkey && rm -f {tmp_path}/sshkey && ansible-playbook main.yaml"
    ]
Exemplo n.º 6
0
def test_prepare_env_sshkey(mocker):
    rc = BaseConfig()

    value = '01234567890'
    sshkey_side_effect = partial(load_file_side_effect, 'env/ssh_key', value)

    mocker.patch.object(rc.loader, 'load_file', side_effect=sshkey_side_effect)
    rc._prepare_env()
    assert rc.ssh_key_data == value
Exemplo n.º 7
0
def test_prepare_env_sshkey():
    rc = BaseConfig(private_data_dir='/tmp')

    value = '01234567890'
    sshkey_side_effect = partial(load_file_side_effect, 'env/ssh_key', value)

    with patch.object(rc.loader, 'load_file', side_effect=sshkey_side_effect):
        rc._prepare_env()
        assert rc.ssh_key_data == value
Exemplo n.º 8
0
def test_prepare_environment_pexpect_defaults():
    rc = BaseConfig()
    rc._prepare_env()

    assert len(rc.expect_passwords) == 2
    assert TIMEOUT in rc.expect_passwords
    assert rc.expect_passwords[TIMEOUT] is None
    assert EOF in rc.expect_passwords
    assert rc.expect_passwords[EOF] is None
Exemplo n.º 9
0
def test_wrap_args_with_ssh_agent_silent():
    rc = BaseConfig(private_data_dir='/tmp')
    res = rc.wrap_args_with_ssh_agent(['ansible-playbook', 'main.yaml'],
                                      '/tmp/sshkey',
                                      silence_ssh_add=True)
    assert res == [
        'ssh-agent', 'sh', '-c',
        "trap 'rm -f /tmp/sshkey' EXIT && ssh-add /tmp/sshkey 2>/dev/null && rm -f /tmp/sshkey && ansible-playbook main.yaml"
    ]
Exemplo n.º 10
0
def test_check_not_safe_to_mount_file(not_safe, mocker):
    """Ensure unsafe directories for a given file are not mounted"""
    file_path = os.path.join(not_safe, "file.txt")
    with pytest.raises(ConfigurationError):
        bc = BaseConfig()
        mocker.patch("os.path.exists", return_value=True)
        bc._update_volume_mount_paths(args_list=[],
                                      src_mount_path=file_path,
                                      dst_mount_path=None)
Exemplo n.º 11
0
def test_prepare_env_defaults():
    with patch('os.path.exists') as path_exists:
        path_exists.return_value = True
        rc = BaseConfig(private_data_dir='/tmp')
        rc._prepare_env()
        assert rc.idle_timeout is None
        assert rc.job_timeout is None
        assert rc.pexpect_timeout == 5
        assert rc.cwd == '/tmp/project'
Exemplo n.º 12
0
def test_prepare_env_ansible_vars(mocker, tmp_path):
    mocker.patch.dict(
        'os.environ', {
            'PYTHONPATH': '/python_path_via_environ',
            'AWX_LIB_DIRECTORY': '/awx_lib_directory_via_environ',
        })

    artifact_dir = tmp_path.joinpath('some_artifacts')
    rc = BaseConfig(artifact_dir=artifact_dir.as_posix())
    rc.ssh_key_data = None
    rc.env = {}
    rc.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS

    rc._prepare_env()

    assert not hasattr(rc, 'ssh_key_path')
    assert not hasattr(rc, 'command')

    assert rc.env['ANSIBLE_STDOUT_CALLBACK'] == 'awx_display'
    assert rc.env['ANSIBLE_RETRY_FILES_ENABLED'] == 'False'
    assert rc.env['ANSIBLE_HOST_KEY_CHECKING'] == 'False'
    assert rc.env['AWX_ISOLATED_DATA_DIR'] == artifact_dir.joinpath(
        rc.ident).as_posix()
    assert rc.env['PYTHONPATH'] == '/python_path_via_environ:/awx_lib_directory_via_environ', \
        "PYTHONPATH is the union of the env PYTHONPATH and AWX_LIB_DIRECTORY"

    del rc.env['PYTHONPATH']
    os.environ['PYTHONPATH'] = "/foo/bar/python_path_via_environ"
    rc._prepare_env()
    assert rc.env['PYTHONPATH'] == "/foo/bar/python_path_via_environ:/awx_lib_directory_via_environ", \
        "PYTHONPATH is the union of the explicit env['PYTHONPATH'] override and AWX_LIB_DIRECTORY"
Exemplo n.º 13
0
def test_prepare_env_settings():
    rc = BaseConfig(private_data_dir='/tmp')

    value = {'test': 'string'}
    settings_side_effect = partial(load_file_side_effect, 'env/settings',
                                   value)

    with patch.object(rc.loader, 'load_file',
                      side_effect=settings_side_effect):
        rc._prepare_env()
        assert rc.settings == value
Exemplo n.º 14
0
def test_prepare_env_settings(mocker):
    rc = BaseConfig()

    value = {'test': 'string'}
    settings_side_effect = partial(load_file_side_effect, 'env/settings',
                                   value)

    mocker.patch.object(rc.loader,
                        'load_file',
                        side_effect=settings_side_effect)
    rc._prepare_env()
    assert rc.settings == value
Exemplo n.º 15
0
def test_prepare_with_ssh_key(open_fifo_write_mock):
    rc = BaseConfig(private_data_dir='/tmp')
    rc.artifact_dir = '/tmp/artifact'
    rc.env = {}
    rc.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS
    rc.ssh_key_data = '01234567890'
    rc.command = 'ansible-playbook'
    rc.cmdline_args = []

    with patch.dict('os.environ', {'AWX_LIB_DIRECTORY': '/tmp/artifact'}):
        rc._prepare_env()

    assert rc.ssh_key_path == '/tmp/artifact/ssh_key_data'
    assert open_fifo_write_mock.called
Exemplo n.º 16
0
def test_base_config_with_artifact_dir(tmp_path, patch_private_data_dir):
    rc = BaseConfig(
        artifact_dir=tmp_path.joinpath('this-is-some-dir').as_posix())
    assert rc.artifact_dir == tmp_path.joinpath('this-is-some-dir').joinpath(
        rc.ident).as_posix()

    # Check that the private data dir is placed in our default location with our default prefix
    # and has some extra uniqueness on the end.
    base_private_data_dir = tmp_path.joinpath('.ansible-runner-').as_posix()
    assert rc.private_data_dir.startswith(base_private_data_dir)
    assert len(rc.private_data_dir) > len(base_private_data_dir)

    rc._prepare_env()
    assert not tmp_path.joinpath('artifacts').exists()
    assert tmp_path.joinpath('this-is-some-dir').exists()
Exemplo n.º 17
0
def test_prepare_env_passwords():
    rc = BaseConfig(private_data_dir='/tmp')

    value = {'^SSH [pP]assword.*$': 'secret'}
    password_side_effect = partial(load_file_side_effect, 'env/passwords',
                                   value)

    with patch.object(rc.loader, 'load_file',
                      side_effect=password_side_effect):
        rc._prepare_env()
        rc.expect_passwords.pop(TIMEOUT)
        rc.expect_passwords.pop(EOF)
        assert len(rc.expect_passwords) == 1
        assert isinstance(list(rc.expect_passwords.keys())[0], Pattern)
        assert 'secret' in rc.expect_passwords.values()
Exemplo n.º 18
0
def test_src_dst_all_relative_dirs(src, dst, labels, relative, mocker):
    mocker.patch("os.path.exists", return_value=True)
    mocker.patch("os.path.isdir", return_value=True)
    """Ensure src is resolved and dest mapped to workdir when relative"""
    relative_src = f"{relative}{src.path}"
    relative_dst = f"{relative}{dst.path}"
    workdir = "/workdir"
    src_str = os.path.join(resolve_path(relative_src), "")
    dst_str = os.path.join(resolve_path(os.path.join(workdir, relative_dst)),
                           "")
    expected = generate_volmount_args(src_str=src_str,
                                      dst_str=dst_str,
                                      labels=labels)

    result = []
    BaseConfig(container_workdir=workdir)._update_volume_mount_paths(
        args_list=result,
        src_mount_path=relative_src,
        dst_mount_path=relative_dst,
        labels=labels)

    explanation = (
        f"provided: {relative_src}:{relative_dst}",
        f"got: {result}",
        f"expected {expected}",
    )
    assert result == expected, explanation
    assert all(part.endswith('/')
               for part in result[1].split(':')[0:1]), explanation
Exemplo n.º 19
0
def test_prepare_environment_vars_only_strings():
    rc = BaseConfig(private_data_dir="/tmp", envvars=dict(D='D'))

    value = dict(A=1, B=True, C="foo")
    envvar_side_effect = partial(load_file_side_effect, 'env/envvars', value)

    with patch.object(rc.loader, 'load_file', side_effect=envvar_side_effect):
        rc._prepare_env()
        assert 'A' in rc.env
        assert isinstance(rc.env['A'], six.string_types)
        assert 'B' in rc.env
        assert isinstance(rc.env['B'], six.string_types)
        assert 'C' in rc.env
        assert isinstance(rc.env['C'], six.string_types)
        assert 'D' in rc.env
        assert rc.env['D'] == 'D'
Exemplo n.º 20
0
def test_base_config_init_with_ident(tmp_path):
    rc = BaseConfig(private_data_dir=tmp_path.as_posix(), ident='test')
    assert rc.private_data_dir == tmp_path.as_posix()
    assert rc.ident == 'test'
    assert rc.artifact_dir == tmp_path.joinpath('artifacts').joinpath(
        'test').as_posix()
    assert isinstance(rc.loader, ArtifactLoader)
Exemplo n.º 21
0
def test_prepare_with_ssh_key(mocker, tmp_path):
    open_fifo_write_mock = mocker.patch(
        'ansible_runner.config._base.open_fifo_write')
    custom_artifacts = tmp_path.joinpath('custom_arts')

    rc = BaseConfig(private_data_dir=tmp_path.as_posix(),
                    artifact_dir=custom_artifacts.as_posix())
    rc.artifact_dir = custom_artifacts.as_posix()
    rc.env = {}
    rc.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS
    rc.ssh_key_data = '01234567890'
    rc.command = 'ansible-playbook'
    rc.cmdline_args = []
    rc._prepare_env()

    assert rc.ssh_key_path == custom_artifacts.joinpath(
        'ssh_key_data').as_posix()
    assert open_fifo_write_mock.called
Exemplo n.º 22
0
def test_base_config_init_defaults():
    rc = BaseConfig(private_data_dir='/tmp')
    assert rc.private_data_dir == '/tmp'
    assert rc.ident is not None
    assert rc.process_isolation is False
    assert rc.fact_cache_type == 'jsonfile'
    assert rc.json_mode is False
    assert rc.quiet is False
    assert rc.quiet is False
    assert rc.rotate_artifacts == 0
    assert rc.artifact_dir == os.path.join('/tmp/artifacts/%s' % rc.ident)
    assert isinstance(rc.loader, ArtifactLoader)
Exemplo n.º 23
0
def test_base_config_init_defaults(tmp_path):
    rc = BaseConfig(private_data_dir=tmp_path.as_posix())
    assert rc.private_data_dir == tmp_path.as_posix()
    assert rc.ident is not None
    assert rc.process_isolation is False
    assert rc.fact_cache_type == 'jsonfile'
    assert rc.json_mode is False
    assert rc.quiet is False
    assert rc.quiet is False
    assert rc.rotate_artifacts == 0
    assert rc.artifact_dir == tmp_path.joinpath('artifacts').joinpath(
        rc.ident).as_posix()
    assert isinstance(rc.loader, ArtifactLoader)
Exemplo n.º 24
0
def test_prepare_env_ansible_vars():
    rc = BaseConfig(private_data_dir='/tmp')
    rc.ssh_key_data = None
    rc.artifact_dir = '/tmp/artifact'
    rc.env = {}
    rc.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS

    rc._prepare_env()

    assert not hasattr(rc, 'ssh_key_path')
    assert not hasattr(rc, 'command')

    assert rc.env['ANSIBLE_STDOUT_CALLBACK'] == 'awx_display'
    assert rc.env['ANSIBLE_RETRY_FILES_ENABLED'] == 'False'
    assert rc.env['ANSIBLE_HOST_KEY_CHECKING'] == 'False'
    assert rc.env['AWX_ISOLATED_DATA_DIR'] == '/tmp/artifact'
    assert rc.env['PYTHONPATH'] == '/python_path_via_environ:/awx_lib_directory_via_environ', \
        "PYTHONPATH is the union of the env PYTHONPATH and AWX_LIB_DIRECTORY"

    del rc.env['PYTHONPATH']
    os.environ['PYTHONPATH'] = "/foo/bar/python_path_via_environ"
    rc._prepare_env()
    assert rc.env['PYTHONPATH'] == "/foo/bar/python_path_via_environ:/awx_lib_directory_via_environ", \
        "PYTHONPATH is the union of the explicit env['PYTHONPATH'] override and AWX_LIB_DIRECTORY"
Exemplo n.º 25
0
def test_duplicate_detection_dst(path, mocker):
    mocker.patch("os.path.exists", return_value=True)
    mocker.patch("os.path.isdir", return_value=True)
    """Ensure no duplicate volumne mount entries are created"""
    base_config = BaseConfig()

    def generate(args_list):
        for entry in dir_variations:
            for label in labels:
                base_config._update_volume_mount_paths(
                    args_list=first_pass,
                    src_mount_path=path.path,
                    dst_mount_path=entry.path,
                    labels=label,
                )

    first_pass = []
    generate(first_pass)
    second_pass = first_pass[:]
    generate(second_pass)
    assert first_pass == second_pass
Exemplo n.º 26
0
def test_src_dst_all_dirs(src, dst, labels, mocker):
    mocker.patch("os.path.exists", return_value=True)
    mocker.patch("os.path.isdir", return_value=True)
    """Ensure src and dest end with trailing slash"""
    src_str = os.path.join(resolve_path(src.path), "")
    dst_str = os.path.join(resolve_path(dst.path), "")
    expected = generate_volmount_args(src_str=src_str,
                                      dst_str=dst_str,
                                      labels=labels)

    result = []
    BaseConfig()._update_volume_mount_paths(args_list=result,
                                            src_mount_path=src.path,
                                            dst_mount_path=dst.path,
                                            labels=labels)

    explanation = (
        f"provided: {src.path}:{dst.path}",
        f"got: {result}",
        f"expected {expected}",
    )
    assert result == expected, explanation
    assert all(part.endswith('/')
               for part in result[1].split(':')[0:1]), explanation
Exemplo n.º 27
0
def test_base_config_project_dir(tmp_path):
    rc = BaseConfig(private_data_dir=tmp_path.as_posix(),
                    project_dir='/another/path')
    assert rc.project_dir == '/another/path'
    rc = BaseConfig(private_data_dir=tmp_path.as_posix())
    assert rc.project_dir == tmp_path.joinpath('project').as_posix()
Exemplo n.º 28
0
def test_containerization_settings(tmp_path, runtime, mocker):
    mocker.patch.dict('os.environ', {'HOME': str(tmp_path)}, clear=True)
    tmp_path.joinpath('.ssh').mkdir()

    mock_containerized = mocker.patch(
        'ansible_runner.config._base.BaseConfig.containerized',
        new_callable=mocker.PropertyMock)
    mock_containerized.return_value = True

    rc = BaseConfig(private_data_dir=tmp_path)
    rc.ident = 'foo'
    rc.cmdline_args = ['main.yaml', '-i', '/tmp/inventory']
    rc.command = ['ansible-playbook'] + rc.cmdline_args
    rc.process_isolation = True
    rc.runner_mode = 'pexpect'
    rc.process_isolation_executable = runtime
    rc.container_image = 'my_container'
    rc.container_volume_mounts = ['/host1:/container1', 'host2:/container2']
    rc.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS
    rc._prepare_env()
    rc._handle_command_wrap(rc.execution_mode, rc.cmdline_args)

    extra_container_args = []
    if runtime == 'podman':
        extra_container_args = ['--quiet']
    else:
        extra_container_args = [f'--user={os.getuid()}']

    expected_command_start = [
        runtime,
        'run',
        '--rm',
        '--tty',
        '--interactive',
        '--workdir',
        '/runner/project',
        '-v',
        '{}/.ssh/:/home/runner/.ssh/'.format(str(tmp_path)),
        '-v',
        '{}/.ssh/:/root/.ssh/'.format(str(tmp_path)),
    ]

    if runtime == 'podman':
        expected_command_start.extend(['--group-add=root', '--ipc=host'])

    expected_command_start.extend([
        '-v',
        '{}/artifacts/:/runner/artifacts/:Z'.format(rc.private_data_dir),
        '-v',
        '{}/:/runner/:Z'.format(rc.private_data_dir),
        '--env-file',
        '{}/env.list'.format(rc.artifact_dir),
    ])

    expected_command_start.extend(extra_container_args)

    expected_command_start.extend([
        '--name',
        'ansible_runner_foo',
        'my_container',
        'ansible-playbook',
        'main.yaml',
        '-i',
        '/tmp/inventory',
    ])

    assert expected_command_start == rc.command
Exemplo n.º 29
0
def test_containerization_unsafe_write_setting(tmp_path, runtime, mocker):
    mock_containerized = mocker.patch(
        'ansible_runner.config._base.BaseConfig.containerized',
        new_callable=mocker.PropertyMock)

    rc = BaseConfig(private_data_dir=tmp_path)
    rc.ident = 'foo'
    rc.cmdline_args = ['main.yaml', '-i', '/tmp/inventory']
    rc.command = ['ansible-playbook'] + rc.cmdline_args
    rc.process_isolation = True
    rc.runner_mode = 'pexpect'
    rc.process_isolation_executable = runtime
    rc.container_image = 'my_container'
    rc.container_volume_mounts = ['/host1:/container1', 'host2:/container2']
    mock_containerized.return_value = True
    rc.execution_mode = BaseExecutionMode.ANSIBLE_COMMANDS
    rc._prepare_env()
    rc._handle_command_wrap(rc.execution_mode, rc.cmdline_args)

    expected = {
        'docker': None,
        'podman': '1',
    }

    assert rc.env.get('ANSIBLE_UNSAFE_WRITES') == expected[runtime]
Exemplo n.º 30
0
def test_combine_python_and_file_settings(project_fixtures):
    rc = BaseConfig(private_data_dir=str(project_fixtures / 'job_env'),
                    settings={'job_timeout': 40})
    rc._prepare_env()
    assert rc.settings == {'job_timeout': 40, 'process_isolation': True}