Example #1
0
def test_fetch_url_json_fail(monkeypatch, return_value, accept_errors, result):
    module = get_module_mock()
    hetzner.fetch_url = MagicMock(return_value=return_value)

    with pytest.raises(ModuleFailException) as exc:
        hetzner.fetch_url_json(module,
                               'https://foo/bar',
                               accept_errors=accept_errors)

    assert exc.value.fail_msg == result
    assert exc.value.fail_kwargs == dict()
Example #2
0
def test_fetch_url_json(monkeypatch, return_value, accept_errors, result):
    module = get_module_mock()
    hetzner.fetch_url = MagicMock(return_value=return_value)

    assert hetzner.fetch_url_json(module,
                                  'https://foo/bar',
                                  accept_errors=accept_errors) == result
def main():
    argument_spec = dict(
        server_ip=dict(type='str', required=True),
        wait_for_configured=dict(type='bool', default=True),
        wait_delay=dict(type='int', default=10),
        timeout=dict(type='int', default=180),
    )
    argument_spec.update(HETZNER_DEFAULT_ARGUMENT_SPEC)
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )

    server_ip = module.params['server_ip']

    # https://robot.your-server.de/doc/webservice/en.html#get-firewall-server-ip
    url = "{0}/firewall/{1}".format(BASE_URL, server_ip)
    if module.params['wait_for_configured']:
        try:
            result, error = fetch_url_json_with_retries(
                module,
                url,
                check_done_callback=firewall_configured,
                check_done_delay=module.params['wait_delay'],
                check_done_timeout=module.params['timeout'],
            )
        except CheckDoneTimeoutException as dummy:
            module.fail_json(
                msg='Timeout while waiting for firewall to be configured.')
    else:
        result, error = fetch_url_json(module, url)

    firewall = result['firewall']
    if not firewall.get('rules'):
        firewall['rules'] = dict()
        for ruleset in ['input']:
            firewall['rules'][ruleset] = []

    module.exit_json(
        changed=False,
        firewall=firewall,
    )
def main():
    argument_spec = dict(
        server_ip=dict(type='str', required=True),
        port=dict(type='str', default='main', choices=['main', 'kvm']),
        state=dict(type='str',
                   default='present',
                   choices=['present', 'absent']),
        whitelist_hos=dict(type='bool'),
        rules=dict(type='dict',
                   options=dict(input=dict(
                       type='list',
                       elements='dict',
                       options=dict(
                           name=dict(type='str'),
                           ip_version=dict(type='str',
                                           required=True,
                                           choices=['ipv4', 'ipv6']),
                           dst_ip=dict(type='str'),
                           dst_port=dict(type='str'),
                           src_ip=dict(type='str'),
                           src_port=dict(type='str'),
                           protocol=dict(type='str'),
                           tcp_flags=dict(type='str'),
                           action=dict(type='str',
                                       required=True,
                                       choices=['accept', 'discard']),
                       )), )),
        update_timeout=dict(type='int', default=30),
        wait_for_configured=dict(type='bool', default=True),
        wait_delay=dict(type='int', default=10),
        timeout=dict(type='int', default=180),
    )
    argument_spec.update(HETZNER_DEFAULT_ARGUMENT_SPEC)
    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )

    # Sanitize input
    module.params['status'] = 'active' if (module.params['state']
                                           == 'present') else 'disabled'
    if module.params['rules'] is None:
        module.params['rules'] = {}
    if module.params['rules'].get('input') is None:
        module.params['rules']['input'] = []

    server_ip = module.params['server_ip']

    # https://robot.your-server.de/doc/webservice/en.html#get-firewall-server-ip
    url = "{0}/firewall/{1}".format(BASE_URL, server_ip)
    if module.params['wait_for_configured']:
        try:
            result, error = fetch_url_json_with_retries(
                module,
                url,
                check_done_callback=firewall_configured,
                check_done_delay=module.params['wait_delay'],
                check_done_timeout=module.params['timeout'],
            )
        except CheckDoneTimeoutException as dummy:
            module.fail_json(
                msg='Timeout while waiting for firewall to be configured.')
    else:
        result, error = fetch_url_json(module, url)
        if not firewall_configured(result, error):
            module.fail_json(
                msg=
                'Firewall configuration cannot be read as it is not configured.'
            )

    full_before = result['firewall']
    if not full_before.get('rules'):
        full_before['rules'] = create_default_rules_object()
    before = restrict_firewall_config(full_before)

    # Build wanted (after) state and compare
    after = dict(before)
    changed = False
    changed |= update(before, after, module.params, 'port')
    changed |= update(before, after, module.params, 'status')
    changed |= update(before, after, module.params, 'whitelist_hos')
    after['rules'] = create_default_rules_object()
    if module.params['status'] == 'active':
        for ruleset in RULES:
            changed |= update_rules(before, after, module.params, ruleset)

    # Update if different
    construct_result = True
    construct_status = None
    if changed and not module.check_mode:
        # https://robot.your-server.de/doc/webservice/en.html#post-firewall-server-ip
        url = "{0}/firewall/{1}".format(BASE_URL, server_ip)
        headers = {"Content-type": "application/x-www-form-urlencoded"}
        data = dict(after)
        data['whitelist_hos'] = str(data['whitelist_hos']).lower()
        del data['rules']
        for ruleset in RULES:
            encode_rule(data, ruleset, after)
        result, error = fetch_url_json(
            module,
            url,
            method='POST',
            timeout=module.params['update_timeout'],
            data=urlencode(data),
            headers=headers,
        )
        if module.params['wait_for_configured'] and not firewall_configured(
                result, error):
            try:
                result, error = fetch_url_json_with_retries(
                    module,
                    url,
                    check_done_callback=firewall_configured,
                    check_done_delay=module.params['wait_delay'],
                    check_done_timeout=module.params['timeout'],
                    skip_first=True,
                )
            except CheckDoneTimeoutException as e:
                result, error = e.result, e.error
                module.warn(
                    'Timeout while waiting for firewall to be configured.')

        full_after = result['firewall']
        if not full_after.get('rules'):
            full_after['rules'] = create_default_rules_object()
        construct_status = full_after['status']
        if construct_status != 'in process':
            # Only use result if configuration is done, so that diff will be ok
            after = restrict_firewall_config(full_after)
            construct_result = False

    if construct_result:
        # Construct result (used for check mode, and configuration still in process)
        full_after = dict(full_before)
        for k, v in after.items():
            if k != 'rules':
                full_after[k] = after[k]
        if construct_status is not None:
            # We want 'in process' here
            full_after['status'] = construct_status
        full_after['rules'] = dict()
        for ruleset in RULES:
            full_after['rules'][ruleset] = after['rules'][ruleset]

    module.exit_json(
        changed=changed,
        diff=dict(
            before=before,
            after=after,
        ),
        firewall=full_after,
    )