def set_failover(module, ip, value, timeout=180): ''' Set current routing target of failover IP. Return a pair ``(value, changed)``. The value ``None`` for ``value`` represents unrouted. See https://robot.your-server.de/doc/webservice/en.html#post-failover-failover-ip and https://robot.your-server.de/doc/webservice/en.html#delete-failover-failover-ip ''' url = "{0}/failover/{1}".format(BASE_URL, ip) if value is None: result, error = fetch_url_json( module, url, method='DELETE', timeout=timeout, accept_errors=['FAILOVER_ALREADY_ROUTED']) else: headers = {"Content-type": "application/x-www-form-urlencoded"} data = dict(active_server_ip=value, ) result, error = fetch_url_json( module, url, method='POST', timeout=timeout, data=urlencode(data), headers=headers, accept_errors=['FAILOVER_ALREADY_ROUTED']) if error is not None: return value, False else: return result['failover']['active_server_ip'], True
def test_fetch_url_json_fail(monkeypatch, return_value, accept_errors, result): module = get_module_mock() robot.fetch_url = MagicMock(return_value=return_value) with pytest.raises(ModuleFailException) as exc: robot.fetch_url_json(module, 'https://foo/bar', accept_errors=accept_errors) assert exc.value.fail_msg == result assert exc.value.fail_kwargs == dict()
def test_fetch_url_json(monkeypatch, return_value, accept_errors, result): module = get_module_mock() robot.fetch_url = MagicMock(return_value=return_value) assert robot.fetch_url_json(module, 'https://foo/bar', accept_errors=accept_errors) == result
def get_failover_record(module, ip): ''' Get information record of failover IP. See https://robot.your-server.de/doc/webservice/en.html#get-failover-failover-ip ''' url = "{0}/failover/{1}".format(BASE_URL, ip) result, error = fetch_url_json(module, url) if 'failover' not in result: module.fail_json(msg='Cannot interpret result: {0}'.format( json.dumps(result, sort_keys=True))) return result['failover']
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(ROBOT_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(ROBOT_DEFAULT_ARGUMENT_SPEC) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if not HAS_IPADDRESS: module.fail_json(msg=missing_required_lib('ipaddress'), exception=IPADDRESS_IMP_ERR) # 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, )