From 2607c7305cca23a2e4bf85e3e264daa409c4ba85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
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

