https://fedorahosted.org/sssd/ticket/1689
Now if first full refresh fails because the data provider is offline, we take following steps:
1. schedule another first full refresh after 2, 4, 8, 16 minutes 2. add an online callback that will perform first full refresh if we know that we are online sooner than the timer is fired
From 57467405beee21ff777e182a42e9ecdca0f25b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]> Date: Fri, 14 Dec 2012 13:15:53 +0100 Subject: [PATCH 1/4] add sdap_sudo_schedule_refresh() Reduces amount of code duplication. --- src/providers/ldap/sdap_sudo.c | 116 +++++++++++++++++++++++++---------------- src/providers/ldap/sdap_sudo.h | 6 +++ 2 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index 2893820776d55f4ee73e410b213f4f9c901f556c..2c6c7712e1b256f6ddc4f72f39c0715fc4444719 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -88,6 +88,13 @@ static void sdap_sudo_periodical_full_refresh_done(struct tevent_req *req); static void sdap_sudo_periodical_smart_refresh_done(struct tevent_req *req); +static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, + struct sdap_sudo_ctx *sudo_ctx, + enum sdap_sudo_refresh_type refresh, + tevent_req_fn callback, + time_t delay, + time_t timeout); + static int sdap_sudo_schedule_full_refresh(struct sdap_sudo_ctx *sudo_ctx, time_t delay); @@ -200,12 +207,11 @@ static void sdap_sudo_get_hostinfo_done(struct tevent_req *req) static int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx) { struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx; - struct tevent_req *req; time_t smart_default; time_t smart_interval; time_t full_interval; time_t last_full; - struct timeval tv; + time_t delay; int ret; smart_interval = dp_opt_get_int(id_ctx->opts->basic, @@ -252,7 +258,7 @@ static int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx) * clients requesting sudo information won't get an * immediate reply with no entries */ - tv = tevent_timeval_current(); + delay = 0; } else { /* At least one update has previously run, * so clients will get cached data. @@ -262,24 +268,19 @@ static int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx) */ /* delay at least by 10s */ - tv = tevent_timeval_current_ofs(10, 0); + delay = 10; } - req = sdap_sudo_timer_send(sudo_ctx, id_ctx->be->ev, sudo_ctx, - tv, full_interval, - sdap_sudo_full_refresh_send); - if (req == NULL) { + ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, + SDAP_SUDO_REFRESH_FULL, + sdap_sudo_periodical_first_refresh_done, + delay, full_interval); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo " "rules! Periodical updates will not work!\n")); - return ENOMEM; + return ret; } - tevent_req_set_callback(req, sdap_sudo_periodical_first_refresh_done, - sudo_ctx); - - DEBUG(SSSDBG_TRACE_FUNC, ("Full refresh scheduled at: %lld\n", - (long long)tv.tv_sec)); - return EOK; } @@ -1111,53 +1112,80 @@ schedule: } } +static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, + struct sdap_sudo_ctx *sudo_ctx, + enum sdap_sudo_refresh_type refresh, + tevent_req_fn callback, + time_t delay, + time_t timeout) +{ + struct tevent_req *req = NULL; + sdap_sudo_timer_fn_t send_fn; + const char *name = NULL; + struct timeval when; + + when = tevent_timeval_current_ofs(delay, 0); + + switch (refresh) { + case SDAP_SUDO_REFRESH_FULL: + send_fn = sdap_sudo_full_refresh_send; + name = "Full refresh"; + break; + case SDAP_SUDO_REFRESH_SMART: + send_fn = sdap_sudo_smart_refresh_send; + name = "Smart refresh"; + break; + case SDAP_SUDO_REFRESH_RULES: + DEBUG(SSSDBG_OP_FAILURE, ("Rules refresh can't be scheduled!\n")); + return EINVAL; + } + + req = sdap_sudo_timer_send(mem_ctx, sudo_ctx->id_ctx->be->ev, sudo_ctx, + when, timeout, send_fn); + if (req == NULL) { + return ENOMEM; + } + + tevent_req_set_callback(req, callback, sudo_ctx); + + DEBUG(SSSDBG_TRACE_FUNC, ("%s scheduled at: %lld\n", + name, (long long)when.tv_sec)); + + return EOK; +} + static int sdap_sudo_schedule_full_refresh(struct sdap_sudo_ctx *sudo_ctx, time_t delay) { - struct tevent_req *req = NULL; - struct timeval tv; + int ret; - /* schedule new refresh */ - tv = tevent_timeval_current_ofs(delay, 0); - req = sdap_sudo_timer_send(sudo_ctx, sudo_ctx->id_ctx->be->ev, sudo_ctx, - tv, delay, sdap_sudo_full_refresh_send); - if (req == NULL) { + ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, + SDAP_SUDO_REFRESH_FULL, + sdap_sudo_periodical_full_refresh_done, + delay, delay); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo " "rules!\n")); - return ENOMEM; + return ret; } - tevent_req_set_callback(req, sdap_sudo_periodical_full_refresh_done, - sudo_ctx); - - DEBUG(SSSDBG_TRACE_FUNC, ("Full refresh scheduled at: %lld\n", - (long long)tv.tv_sec)); - return EOK; } static int sdap_sudo_schedule_smart_refresh(struct sdap_sudo_ctx *sudo_ctx, time_t delay) { - struct sdap_id_ctx *id_ctx = sudo_ctx->id_ctx; - struct tevent_req *req = NULL; - struct timeval tv; + int ret; - /* schedule new refresh */ - tv = tevent_timeval_current_ofs(delay, 0); - req = sdap_sudo_timer_send(sudo_ctx, id_ctx->be->ev, sudo_ctx, - tv, delay, sdap_sudo_smart_refresh_send); - if (req == NULL) { + ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, + SDAP_SUDO_REFRESH_SMART, + sdap_sudo_periodical_smart_refresh_done, + delay, delay); + if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule smart refresh of sudo " "rules!\n")); - return ENOMEM; + return ret; } - tevent_req_set_callback(req, sdap_sudo_periodical_smart_refresh_done, - sudo_ctx); - - DEBUG(SSSDBG_TRACE_FUNC, ("Smart refresh scheduled at: %lld\n", - (long long)tv.tv_sec)); - return EOK; } diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h index f9988d6116f048c3a698f920ed2d9baf9c06b6da..5a12afd591e591792697097e05d8a6fc3a7ec65d 100644 --- a/src/providers/ldap/sdap_sudo.h +++ b/src/providers/ldap/sdap_sudo.h @@ -33,6 +33,12 @@ struct sdap_sudo_ctx { bool full_refresh_done; }; +enum sdap_sudo_refresh_type { + SDAP_SUDO_REFRESH_FULL, + SDAP_SUDO_REFRESH_SMART, + SDAP_SUDO_REFRESH_RULES +}; + /* Common functions from ldap_sudo.c */ void sdap_sudo_handler(struct be_req *breq); int sdap_sudo_init(struct be_ctx *be_ctx, -- 1.7.11.7
From 179f20a5b25043742167b4de2e9b2ae6fe23c0e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]> Date: Fri, 14 Dec 2012 12:29:50 +0100 Subject: [PATCH 2/4] check dp error in sdap_sudo_full_refresh_done() https://fedorahosted.org/sssd/ticket/1689 --- src/providers/ldap/sdap_sudo.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index 2c6c7712e1b256f6ddc4f72f39c0715fc4444719..c4f422ed6dcac97aa0f418c18185c846e5a753f6 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -615,9 +615,8 @@ static void sdap_sudo_full_refresh_done(struct tevent_req *subreq) ret = sdap_sudo_refresh_recv(state, subreq, &state->dp_error, &state->error, &highest_usn, NULL); talloc_zfree(subreq); - if (ret != EOK) { - tevent_req_error(req, ret); - return; + if (ret != EOK || state->dp_error != DP_ERR_OK || state->error != EOK) { + goto done; } state->sudo_ctx->full_refresh_done = true; @@ -639,6 +638,12 @@ static void sdap_sudo_full_refresh_done(struct tevent_req *subreq) sdap_sudo_set_usn(state->id_ctx->srv_opts, highest_usn); } +done: + if (ret != EOK) { + tevent_req_error(req, ret); + return; + } + tevent_req_done(req); } -- 1.7.11.7
From c670b62a1ee91d0fd746ea0effc9aeb8f470ed93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]> Date: Fri, 14 Dec 2012 12:51:33 +0100 Subject: [PATCH 3/4] sudo: schedule another full refresh in short interval if the first fails https://fedorahosted.org/sssd/ticket/1689 If the first full refresh of sudo rules fails because the data provider is offline, we will schedule another one in 2, 4, ... minutes. --- src/providers/ldap/sdap_sudo.c | 27 +++++++++++++++++++++++++++ src/providers/ldap/sdap_sudo.h | 1 + 2 files changed, 28 insertions(+) diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index c4f422ed6dcac97aa0f418c18185c846e5a753f6..9a780b8eb6f24736b06f64aedcae3ec170a8ac56 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -30,6 +30,8 @@ #include "providers/ldap/sdap_sudo_cache.h" #include "db/sysdb_sudo.h" +#define SUDO_MAX_FIRST_REFRESH_DELAY 16 + struct sdap_sudo_full_refresh_state { struct sdap_sudo_ctx *sudo_ctx; struct sdap_id_ctx *id_ctx; @@ -960,6 +962,7 @@ static void sdap_sudo_periodical_first_refresh_done(struct tevent_req *req) struct tevent_req *subreq = NULL; /* req from sdap_sudo_full_refresh_send() */ struct sdap_sudo_ctx *sudo_ctx = NULL; time_t delay; + time_t timeout; int dp_error = DP_ERR_OK; int error = EOK; int ret; @@ -999,6 +1002,30 @@ schedule: return; } + /* if we are offline, we will try to perform another full refresh */ + if (dp_error == DP_ERR_OFFLINE) { + sudo_ctx->full_refresh_attempts++; + timeout = delay; + delay = sudo_ctx->full_refresh_attempts << 1; + if (delay > SUDO_MAX_FIRST_REFRESH_DELAY) { + delay = SUDO_MAX_FIRST_REFRESH_DELAY; + } + + DEBUG(SSSDBG_TRACE_FUNC, ("Data provider is offline. " + "Scheduling another full refresh in %l minutes.\n", delay)); + + ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, + SDAP_SUDO_REFRESH_FULL, + sdap_sudo_periodical_first_refresh_done, + delay * 60, timeout); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo " + "rules! Periodical updates will not work!\n")); + } + + return; + } + ret = sdap_sudo_schedule_full_refresh(sudo_ctx, delay); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Full periodical refresh will not work.\n")); diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h index 5a12afd591e591792697097e05d8a6fc3a7ec65d..6384c7b811bd34a7b88f9862ab8c9926e48754bb 100644 --- a/src/providers/ldap/sdap_sudo.h +++ b/src/providers/ldap/sdap_sudo.h @@ -31,6 +31,7 @@ struct sdap_sudo_ctx { bool use_host_filter; bool full_refresh_done; + int full_refresh_attempts; }; enum sdap_sudo_refresh_type { -- 1.7.11.7
From 2607c7305cca23a2e4bf85e3e264daa409c4ba85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <[email protected]> Date: Fri, 14 Dec 2012 14:19:44 +0100 Subject: [PATCH 4/4] sudo: do full refresh when data provider is back online https://fedorahosted.org/sssd/ticket/1689 Add a online callback if the first full refresh fails due to the provider beeing offline so we can perform the refresh as soon as possible. --- src/providers/ldap/sdap_sudo.c | 79 ++++++++++++++++++++++++++++++++++++++---- src/providers/ldap/sdap_sudo.h | 3 ++ 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/providers/ldap/sdap_sudo.c b/src/providers/ldap/sdap_sudo.c index 9a780b8eb6f24736b06f64aedcae3ec170a8ac56..53aa6d4a047a2e288eb2384893b2e8c81b94ea08 100644 --- a/src/providers/ldap/sdap_sudo.c +++ b/src/providers/ldap/sdap_sudo.c @@ -95,7 +95,8 @@ static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, enum sdap_sudo_refresh_type refresh, tevent_req_fn callback, time_t delay, - time_t timeout); + time_t timeout, + struct tevent_req **_req); static int sdap_sudo_schedule_full_refresh(struct sdap_sudo_ctx *sudo_ctx, time_t delay); @@ -276,7 +277,7 @@ static int sdap_sudo_setup_periodical_refresh(struct sdap_sudo_ctx *sudo_ctx) ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, SDAP_SUDO_REFRESH_FULL, sdap_sudo_periodical_first_refresh_done, - delay, full_interval); + delay, full_interval, NULL); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo " "rules! Periodical updates will not work!\n")); @@ -547,6 +548,8 @@ static struct tevent_req *sdap_sudo_full_refresh_send(TALLOC_CTX *mem_ctx, return NULL; } + sudo_ctx->full_refresh_in_progress = true; + state->sudo_ctx = sudo_ctx; state->id_ctx = id_ctx; state->sysdb = id_ctx->be->sysdb; @@ -641,6 +644,8 @@ static void sdap_sudo_full_refresh_done(struct tevent_req *subreq) } done: + state->sudo_ctx->full_refresh_in_progress = false; + if (ret != EOK) { tevent_req_error(req, ret); return; @@ -957,6 +962,46 @@ static int sdap_sudo_smart_refresh_recv(struct tevent_req *req, NULL, NULL); } +static void sdap_sudo_full_refresh_online_cb(void *pvt) +{ + struct sdap_sudo_ctx *sudo_ctx = NULL; + time_t timeout; + int ret; + + sudo_ctx = talloc_get_type(pvt, struct sdap_sudo_ctx); + + /* remove online callback */ + talloc_zfree(sudo_ctx->first_refresh_online_cb); + + /* schedule new first refresh only if this callback wasn't triggered + * by ongoing full refresh */ + if (sudo_ctx->full_refresh_in_progress) { + return; + } + + /* otherwise cancel the concurrent timer for full refresh */ + talloc_zfree(sudo_ctx->first_refresh_timer); + + /* and fire full refresh immediately */ + timeout = dp_opt_get_int(sudo_ctx->id_ctx->opts->basic, + SDAP_SUDO_FULL_REFRESH_INTERVAL); + if (timeout == 0) { + /* runtime configuration change? */ + DEBUG(SSSDBG_TRACE_FUNC, ("Periodical full refresh of sudo rules " + "is disabled\n")); + return; + } + + ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, + SDAP_SUDO_REFRESH_FULL, + sdap_sudo_periodical_first_refresh_done, + 0, timeout, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo " + "rules! Periodical updates will not work!\n")); + } +} + static void sdap_sudo_periodical_first_refresh_done(struct tevent_req *req) { struct tevent_req *subreq = NULL; /* req from sdap_sudo_full_refresh_send() */ @@ -990,6 +1035,9 @@ static void sdap_sudo_periodical_first_refresh_done(struct tevent_req *req) schedule: sudo_ctx = tevent_req_callback_data(req, struct sdap_sudo_ctx); + if (sudo_ctx->first_refresh_timer == req) { + sudo_ctx->first_refresh_timer = NULL; + } talloc_zfree(req); /* full refresh */ @@ -1012,17 +1060,27 @@ schedule: } DEBUG(SSSDBG_TRACE_FUNC, ("Data provider is offline. " - "Scheduling another full refresh in %l minutes.\n", delay)); + "Scheduling another full refresh in %lld minutes.\n", delay)); ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, SDAP_SUDO_REFRESH_FULL, sdap_sudo_periodical_first_refresh_done, - delay * 60, timeout); + delay * 60, timeout, + &sudo_ctx->first_refresh_timer); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo " "rules! Periodical updates will not work!\n")); } + /* also setup online callback to make sure the refresh is fired as soon + * as possible */ + ret = be_add_online_cb(sudo_ctx->id_ctx->be, sudo_ctx->id_ctx->be, + sdap_sudo_full_refresh_online_cb, + sudo_ctx, &sudo_ctx->first_refresh_online_cb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not set up online callback\n")); + } + return; } @@ -1149,7 +1207,8 @@ static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, enum sdap_sudo_refresh_type refresh, tevent_req_fn callback, time_t delay, - time_t timeout) + time_t timeout, + struct tevent_req **_req) { struct tevent_req *req = NULL; sdap_sudo_timer_fn_t send_fn; @@ -1172,6 +1231,8 @@ static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, return EINVAL; } + + req = sdap_sudo_timer_send(mem_ctx, sudo_ctx->id_ctx->be->ev, sudo_ctx, when, timeout, send_fn); if (req == NULL) { @@ -1183,6 +1244,10 @@ static int sdap_sudo_schedule_refresh(TALLOC_CTX *mem_ctx, DEBUG(SSSDBG_TRACE_FUNC, ("%s scheduled at: %lld\n", name, (long long)when.tv_sec)); + if (_req != NULL) { + *_req = req; + } + return EOK; } @@ -1194,7 +1259,7 @@ static int sdap_sudo_schedule_full_refresh(struct sdap_sudo_ctx *sudo_ctx, ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, SDAP_SUDO_REFRESH_FULL, sdap_sudo_periodical_full_refresh_done, - delay, delay); + delay, delay, NULL); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule full refresh of sudo " "rules!\n")); @@ -1212,7 +1277,7 @@ static int sdap_sudo_schedule_smart_refresh(struct sdap_sudo_ctx *sudo_ctx, ret = sdap_sudo_schedule_refresh(sudo_ctx, sudo_ctx, SDAP_SUDO_REFRESH_SMART, sdap_sudo_periodical_smart_refresh_done, - delay, delay); + delay, delay, NULL); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Unable to schedule smart refresh of sudo " "rules!\n")); diff --git a/src/providers/ldap/sdap_sudo.h b/src/providers/ldap/sdap_sudo.h index 6384c7b811bd34a7b88f9862ab8c9926e48754bb..e2764b90c91470ed64e4c07a792206fa034646a6 100644 --- a/src/providers/ldap/sdap_sudo.h +++ b/src/providers/ldap/sdap_sudo.h @@ -31,7 +31,10 @@ struct sdap_sudo_ctx { bool use_host_filter; bool full_refresh_done; + bool full_refresh_in_progress; int full_refresh_attempts; + struct be_cb *first_refresh_online_cb; + struct tevent_req *first_refresh_timer; }; enum sdap_sudo_refresh_type { -- 1.7.11.7
_______________________________________________ sssd-devel mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
