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

Make failover work over IP families #7658

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
39 changes: 38 additions & 1 deletion src/providers/fail_over.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ str_server_status(enum server_status status)
return "working";
case SERVER_NOT_WORKING:
return "not working";
case SERVER_SECOND_FAMILY:
return "second family";
}

return "unknown server status";
Expand Down Expand Up @@ -481,6 +483,23 @@ service_destructor(struct fo_service *service)
return 0;
}

static int
try_another_family(struct fo_server *server, enum restrict_family family_order) {
if (server == NULL || server->common == NULL || server->common->rhostent == NULL) {
return 0;
}

if (server->common->rhostent->family == AF_INET && family_order == IPV4_FIRST) {
return 1;
}

if (server->common->rhostent->family == AF_INET6 && family_order == IPV6_FIRST) {
return 1;
}

return 0;
}

int
fo_new_service(struct fo_ctx *ctx, const char *name,
datacmp_fn user_data_cmp,
Expand Down Expand Up @@ -937,6 +956,11 @@ get_first_server_entity(struct fo_service *service, struct fo_server **_server)
if (service_works(server) && fo_is_server_primary(server)) {
goto done;
}
if (fo_is_server_primary(server) && try_another_family(server, service->ctx->opts->family_order) ) {
/* set server state shomehow ? */
fo_set_server_status(server, SERVER_SECOND_FAMILY);
goto done;
}
service->active_server = NULL;
}

Expand Down Expand Up @@ -1193,13 +1217,26 @@ fo_resolve_service_server(struct tevent_req *req)
struct resolve_service_state);
struct tevent_req *subreq;
int ret;
enum restrict_family family_restriction;

family_restriction = state->fo_ctx->opts->family_order;
switch (get_server_status(state->server)) {
case SERVER_SECOND_FAMILY:
switch (family_restriction) {
case IPV4_FIRST:
family_restriction = IPV6_ONLY;
break;
case IPV6_FIRST:
family_restriction = IPV4_ONLY;
break;
default:
break;
}
case SERVER_NAME_NOT_RESOLVED: /* Request name resolution. */
subreq = resolv_gethostbyname_send(state->server->common,
state->ev, state->resolv,
state->server->common->name,
state->fo_ctx->opts->family_order,
family_restriction,
default_host_dbs);
if (subreq == NULL) {
tevent_req_error(req, ENOMEM);
Expand Down
1 change: 1 addition & 0 deletions src/providers/fail_over.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum server_status {
SERVER_NAME_NOT_RESOLVED, /* We didn't yet resolved the host name. */
SERVER_RESOLVING_NAME, /* Name resolving is in progress. */
SERVER_NAME_RESOLVED, /* We resolved the host name but didn't try to connect. */
SERVER_SECOND_FAMILY, /* We should try second protocol */
SERVER_WORKING, /* We successfully connected to the server. */
SERVER_NOT_WORKING /* We tried and failed to connect to the server. */
};
Expand Down
1 change: 1 addition & 0 deletions src/providers/fail_over_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ struct fo_resolve_srv_dns_ctx {
char *hostname;
char *sssd_domain;
char *detected_domain;
bool last_family_tried;
};

struct fo_resolve_srv_dns_state {
Expand Down
2 changes: 2 additions & 0 deletions src/tests/fail_over-tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ START_TEST(test_fo_resolve_service)
get_request(ctx, service[0], EOK, 20, PORT_WORKING, -1);
get_request(ctx, service[0], EOK, 20, PORT_WORKING, SERVER_WORKING);
get_request(ctx, service[0], EOK, 20, -1, SERVER_NOT_WORKING);
get_request(ctx, service[0], EOK, 20, PORT_WORKING, SERVER_WORKING);
get_request(ctx, service[0], EOK, 20, -1, SERVER_NOT_WORKING);
get_request(ctx, service[0], EOK, 80, PORT_WORKING, -1);
get_request(ctx, service[0], EOK, 80, PORT_NOT_WORKING, -1);
get_request(ctx, service[0], ENOENT, 0, -1, -1);
Expand Down
31 changes: 30 additions & 1 deletion src/tests/system/tests/test_failover.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from sssd_test_framework.roles.ipa import IPA
from sssd_test_framework.roles.ldap import LDAP
from sssd_test_framework.roles.samba import Samba
from sssd_test_framework.topology import KnownTopologyGroup
from sssd_test_framework.topology import KnownTopologyGroup, KnownTopology


@pytest.mark.parametrize("value, expected", [(None, 31), (15, 31), (60, 60)])
Expand Down Expand Up @@ -80,3 +80,32 @@ def test_failover__reactivation_timeout_is_honored(
assert (
f"Primary server reactivation timeout set to {expected} seconds" in log
), f"'Primary server reactivation timeout set to {expected} seconds' not found in logs!"


@pytest.mark.importance("low")
@pytest.mark.topology(KnownTopology.IPA)
def test_failover__connect_second_family(client: Client, ipa: IPA):
"""
:title: Make sure that we can connect using secondary protocol
:setup:
1. Create user in IPA
2. Set family_order to "ipv6_first"
3. Set IPv6 address in /etc/hosts so it resolves but it
points to non-exesting machine
:steps:
1. Restart SSSD
2. Resolve user
:expectedresults:
1. SSSD goes online, user is resolved
:customerscenario: False
"""
user = "testuser"
ipa.user(user).add()
client.sssd.domain["lookup_family_order"] = "ipv6_first"
client.sssd.domain["debug_level"] = "9"
client.fs.append("/etc/hosts", "cafe:cafe::3 %s" % ipa.host.hostname)
import time
time.sleep(2)
client.sssd.start()
result = client.tools.id(user)
assert result is not None
Loading