Add config reloading
authorNeutron Soutmun <neo.neutron@gmail.com>
Mon, 27 Apr 2009 01:48:29 +0000 (08:48 +0700)
committerNeutron Soutmun <neo.neutron@gmail.com>
Mon, 27 Apr 2009 01:48:29 +0000 (08:48 +0700)
2009-04-27  Neutron Soutmun <neo.neutron@gmail.com>

* src/rahunas.c, src/rh-config.h, src/rh-ipset.c, src/rh-server.{h,c},
  src/rh-task-dbset.c, src/rh-task-ipset.c, src/rh-task-iptables.c,
  src/rh-task-memset.c:
  - Add config reloading by issue SIGHUP.
  - Adjust the tasks to the changes of config reloading.
* example/rahunas.init.in:
  - Add reload function.
  - In restart command, try to start if the process is not running.
* tools/firewall.sh.in: Add the KEEP_SET funtionality.

12 files changed:
ChangeLog
example/rahunas.init.in
src/rahunasd.c
src/rh-config.h
src/rh-ipset.c
src/rh-server.c
src/rh-server.h
src/rh-task-dbset.c
src/rh-task-ipset.c
src/rh-task-iptables.c
src/rh-task-memset.c
tools/firewall.sh.in

index 2e10255..290b744 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2009-04-27  Neutron Soutmun <neo.neutron@gmail.com>
+
+       * src/rahunas.c, src/rh-config.h, src/rh-ipset.c, src/rh-server.{h,c},
+         src/rh-task-dbset.c, src/rh-task-ipset.c, src/rh-task-iptables.c, 
+         src/rh-task-memset.c:
+         - Add config reloading by issue SIGHUP.
+         - Adjust the tasks to the changes of config reloading.
+       * example/rahunas.init.in:
+         - Add reload function.
+         - In restart command, try to start if the process is not running.
+       * tools/firewall.sh.in: Add the KEEP_SET funtionality.
+
 2009-04-23  Neutron Soutmun <neo.neutron@gmail.com>
 
        * example/rahunas.init.in: 
index 0b48aa6..5d0ca69 100755 (executable)
@@ -77,6 +77,20 @@ stop () {
   return 0
 }
 
+reload () {
+  start-stop-daemon --stop --quiet --signal HUP \
+    --pidfile $PID --name $NAME < /dev/null
+  sleep 2
+
+  if test -n "$PID" && kill -0 $PID 2>/dev/null
+  then
+    log_action_end_msg 0
+  else
+    log_action_end_msg 1
+  fi
+  return 0
+}
+
 case "$1" in
   start)
     log_daemon_msg "Starting $DESC" "$NAME"
@@ -102,7 +116,7 @@ case "$1" in
     ;;
   restart)
     log_daemon_msg "Restarting $DESC" "$NAME"
-    stop
+    stop || true
 
     if [ "$RUN_DAEMON" = "yes" ]; then
       if start ; then
@@ -114,6 +128,15 @@ case "$1" in
       log_end_msg "disabled, to enable see $INIT"
     fi
     ;;
+  reload)
+    log_daemon_msg "Reloading $DESC" "$NAME"
+    
+    if reload ; then
+      log_end_msg $?
+    else
+      log_end_msg $?
+    fi
+    ;;
   status)
     status_of_proc -p "$PID" "$DAEMON" "$NAME" && exit 0 || exit $?
     ;;
index 41cd826..fa5e616 100644 (file)
 const char *termstring = '\0';
 pid_t pid, sid;
 
+int getline(int fd, char *buf, size_t size);
+
 struct main_server rh_main_server_instance = {
   .vserver_list = NULL,
   .task_list = NULL,
 };
-
 struct main_server *rh_main_server = &rh_main_server_instance;
 
-int getline(int fd, char *buf, size_t size);
-size_t expired_check(void *data);
-
 void rh_sighandler(int sig)
 {
   switch (sig) {
@@ -51,7 +49,18 @@ void rh_sighandler(int sig)
         exit(EXIT_FAILURE);
       }
       break;
+    case SIGHUP:
+      if (pid == 0) {
+        rh_reload();
+      } else if (pid > 0) {
+        syslog(LOG_NOTICE, "Reloading config files");
+        kill(pid, SIGHUP);
+      } else {
+        syslog(LOG_ERR, "Invalid PID");
+      }
+      break;
   }
+  return;
 }
 
 int getline(int fd, char *buf, size_t size)
@@ -134,14 +143,20 @@ size_t expired_check(void *data)
   }
 }
 
-gboolean polling_expired_check(struct main_server *ms, struct vserver *vs) {
+int polling_expired_check(struct main_server *ms, struct vserver *vs) {
   walk_through_set(&expired_check, vs);
-  return TRUE;
+  return 0;
 }
 
 gboolean polling(gpointer data) {
   struct main_server *ms = (struct main_server *)data;
   struct vserver *vs = NULL;
+  
+  if (ms->polling_blocked) {
+    DP("%s", "Skip polling!");
+    return TRUE;
+  }
+  
   DP("%s", "Start polling!");
   walk_through_vserver(&polling_expired_check, ms);
   return TRUE;
@@ -152,9 +167,47 @@ void rh_exit()
   walk_through_vserver(&rh_task_cleanup, rh_main_server);
   rh_task_stopservice(rh_main_server);
   rh_task_unregister(rh_main_server);
+  unregister_vserver_all(rh_main_server);
   rh_closelog(rh_main_server->main_config->log_file);
 }
 
+void rh_reload()
+{
+  logmsg(RH_LOG_NORMAL, "Reloading config files");
+  /* Block polling */
+  rh_main_server->polling_blocked = 1;
+
+  if (rh_main_server->main_config->log_file != NULL) {
+    syslog(LOG_INFO, "Open log file: %s", 
+           rh_main_server->main_config->log_file);
+    rh_main_server->log_fd = rh_openlog(rh_main_server->main_config->log_file);
+
+    if (!rh_main_server->log_fd) {
+      syslog(LOG_ERR, "Could not open log file %s\n", 
+             rh_main_server->main_config->log_file);
+      exit(EXIT_FAILURE);
+    }
+
+    rh_logselect(rh_main_server->log_fd);
+  }
+
+  /* Get vserver(s) config, again */
+  if (rh_main_server->main_config->conf_dir != NULL) {
+    get_vservers_config(rh_main_server->main_config->conf_dir, rh_main_server);
+  } else {
+    syslog(LOG_ERR, "The main configuration file is incompleted, lack of conf_dir\n");
+    exit(EXIT_FAILURE);
+  }
+
+  walk_through_vserver(&vserver_reload, rh_main_server);
+  vserver_unused_cleanup(rh_main_server);
+  
+  /* Unblock polling */
+  rh_main_server->polling_blocked = 0;
+  DP("Config reload finished");
+  return;
+}
+
 static void
 watch_child(char *argv[])
 {
@@ -255,6 +308,7 @@ void rh_free_member (struct rahunas_member *member)
     free(member->session_id);
 }
 
+
 int main(int argc, char **argv) 
 {
   gchar* addr = "localhost";
@@ -276,7 +330,9 @@ int main(int argc, char **argv)
   GNetXmlRpcServer *server = NULL;
   GMainLoop* main_loop     = NULL;
 
-  signal(SIGTERM, rh_sighandler);
+  signal(SIGTERM, &rh_sighandler);
+  signal(SIGHUP, &rh_sighandler);
+  signal(SIGINT, SIG_IGN);
 
   watch_child(argv);
 
@@ -349,7 +405,8 @@ int main(int argc, char **argv)
   g_timeout_add_seconds (rh_main_server->main_config->polling_interval, 
                          polling, rh_main_server);
 
-
+  walk_through_vserver(&vserver_init_done, rh_main_server);
   logmsg(RH_LOG_NORMAL, "Ready to serve...");
   g_main_loop_run(main_loop);
 
index b3083fe..53ccfd3 100644 (file)
@@ -36,6 +36,7 @@ struct rahunas_main_config {
 struct rahunas_vserver_config {
   char *vserver_name;
   int  vserver_id;
+  int  init_flag;
   char *dev_external;
   char *dev_internal;
   char *vlan;
@@ -81,6 +82,14 @@ enum config_type {
   VSERVER
 };
 
+enum vserver_config_init_flag {
+  VS_NONE,
+  VS_INIT,
+  VS_RELOAD,
+  VS_RESET,
+  VS_DONE
+};
+
 int get_config(const char *cfg_file, union rahunas_config *config);
 int get_value(const char *cfg_file, const char *key, void **data, size_t *len);
 int get_vservers_config(const char *conf_dir, struct main_server *server);
index a5ee646..51c8994 100644 (file)
@@ -397,7 +397,7 @@ int walk_through_set (int (*callback)(void *), struct vserver *vs)
   ip_set_id_t idx;
   socklen_t size, req_size;
   int res = 0;
-
+   
   size = req_size = load_set_list(vs, vs->vserver_config->vserver_name, &idx, 
                                   IP_SET_OP_LIST_SIZE, CMD_LIST); 
 
index 636ed6a..e0faa08 100644 (file)
@@ -8,7 +8,7 @@
 #include "rh-server.h"
 #include "rh-utils.h"
 
-int vserver_exists(GList *vserver_list, int vserver_id, 
+struct vserver *vserver_exists(GList *vserver_list, int vserver_id, 
                    const char *vserver_name)
 {
   GList *runner = g_list_first(vserver_list);
@@ -18,14 +18,14 @@ int vserver_exists(GList *vserver_list, int vserver_id,
     lvserver = (struct vserver *)runner->data;
    
     if (lvserver->vserver_config->vserver_id == vserver_id)
-      return 1; 
+      return lvserver; 
 
     if (strcmp(lvserver->vserver_config->vserver_name, vserver_name) == 0)
-      return 2;
+      return lvserver;
 
     runner = g_list_next(runner); 
   } 
-  return 0;
+  return NULL;
 }
 
 struct vserver *vserver_get_by_id(struct main_server *ms, int search_id)
@@ -53,12 +53,6 @@ int vserver_cleanup(struct vserver *vs)
   if (vs->vserver_config != NULL)
     cleanup_vserver_config(vs->vserver_config);  
 
-  if (vs->v_map != NULL)
-    // TODO: cleanup map
-
-  if (vs->v_set != NULL)
-    // TODO: cleanup set
-
   return 0;
 }
 
@@ -83,10 +77,12 @@ int register_vserver(struct main_server *ms, const char *vserver_cfg_file)
   union rahunas_config *cfg_get = NULL;
   struct rahunas_vserver_config *vserver_config = NULL;
   struct vserver *new_vserver = NULL;
+  struct vserver *old_vserver = NULL;
 
   union rahunas_config config = {
     .rh_vserver.vserver_name = NULL,
     .rh_vserver.vserver_id = VSERVER_ID,
+    .rh_vserver.init_flag = VS_INIT,
     .rh_vserver.dev_external = NULL,
     .rh_vserver.dev_internal = NULL,
     .rh_vserver.vlan = NULL,
@@ -126,6 +122,41 @@ int register_vserver(struct main_server *ms, const char *vserver_cfg_file)
   if (cfg_file == NULL)
     return -1;
 
+  if (get_config(vserver_cfg_file, &config) == 0) {
+    old_vserver = vserver_exists(vserver_list, config.rh_vserver.vserver_id, 
+                    config.rh_vserver.vserver_name);
+
+    if (old_vserver != NULL) {
+      if (old_vserver->dummy_config != NULL) {
+        DP("Cleanup old dummy config");
+        rh_free(&old_vserver->dummy_config);
+      }
+
+      old_vserver->dummy_config = 
+        (struct rahunas_vserver_config *) rh_malloc(sizeof(struct rahunas_vserver_config));
+
+      if (old_vserver->dummy_config == NULL)
+        return -1;
+
+      memset(old_vserver->dummy_config, 0, 
+        sizeof(struct rahunas_vserver_config));
+      memcpy(old_vserver->dummy_config, &config, 
+        sizeof(struct rahunas_vserver_config));
+
+      if (strncmp(config.rh_vserver.vserver_name, 
+            old_vserver->vserver_config->vserver_name, 32) != 0 || 
+          strncmp(config.rh_vserver.clients, 
+            old_vserver->vserver_config->clients, 18) != 0) {
+        old_vserver->vserver_config->init_flag = VS_RESET;
+      } else {
+        old_vserver->vserver_config->init_flag = VS_RELOAD;  
+      }
+      return 1;
+    }
+  } else {
+    return -1;
+  }
+
   vserver_config = (struct rahunas_vserver_config *) rh_malloc(sizeof(struct rahunas_vserver_config));
 
   if (vserver_config == NULL)
@@ -133,18 +164,8 @@ int register_vserver(struct main_server *ms, const char *vserver_cfg_file)
 
   memset(vserver_config, 0, sizeof(struct rahunas_vserver_config));
 
-  if (get_config(vserver_cfg_file, &config) != 0) {
-    rh_free(&config.rh_vserver.vserver_ip);
-    return -1;
-  }
-
   memcpy(vserver_config, &config, sizeof(struct rahunas_vserver_config));
 
-  if (vserver_exists(vserver_list, vserver_config->vserver_id, 
-                     vserver_config->vserver_name)) {
-    return 1;
-  }
-
   new_vserver = (struct vserver *) rh_malloc(sizeof(struct vserver));
 
   if (new_vserver == NULL)
@@ -154,24 +175,46 @@ int register_vserver(struct main_server *ms, const char *vserver_cfg_file)
 
   new_vserver->vserver_config = vserver_config;
 
+  new_vserver->vserver_config->init_flag = VS_INIT;
   ms->vserver_list = g_list_append(ms->vserver_list, new_vserver);
   return 0; 
 }
 
 int unregister_vserver(struct main_server *ms, int vserver_id)
 {
+  GList *vserver_list = ms->vserver_list;
+  GList *runner = g_list_first(vserver_list);
+  struct vserver *lvserver = NULL;
+
+  while (runner != NULL) {
+    lvserver = (struct vserver *)runner->data;
+    if (lvserver->vserver_config->vserver_id == vserver_id) {
+      vserver_cleanup(lvserver);
+
+      ms->vserver_list = g_list_delete_link(ms->vserver_list, runner);
+      break;
+    } else {
+      runner = g_list_next(runner);
+    }
+  }
+  return 0;
 }
 
 int unregister_vserver_all(struct main_server *ms)
 {
   GList *vserver_list = ms->vserver_list;
   GList *runner = g_list_first(vserver_list);
+  GList *deleting = NULL;
   struct vserver *lvserver = NULL;
 
   while (runner != NULL) {
     lvserver = (struct vserver *)runner->data;
     vserver_cleanup(lvserver);
-    runner = g_list_delete_link(runner, runner);
+    deleting = runner;
+    runner = g_list_next(runner);
+
+    cleanup_vserver_config(lvserver->vserver_config);
+    ms->vserver_list = g_list_delete_link(ms->vserver_list, deleting);
   }
   
   return 0;
@@ -193,3 +236,87 @@ int walk_through_vserver(int (*callback)(void *, void *), struct main_server *ms
 
   return 0;
 }
+
+void vserver_init_done(struct main_server *ms, struct vserver *vs)
+{
+  if (vs != NULL) {
+    vs->vserver_config->init_flag = VS_DONE;
+    DP("Virtual Sever (%s) - Configured", vs->vserver_config->vserver_name);
+  }
+}
+
+void vserver_reload(struct main_server *ms, struct vserver *vs)
+{
+  if (vs->vserver_config->init_flag == VS_DONE) {
+    // Indicate the unused virtual server
+    vs->vserver_config->init_flag = VS_NONE;
+    return;
+  }
+
+  while (vs->vserver_config->init_flag != VS_DONE) {
+    if (vs->vserver_config->init_flag == VS_INIT) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Config init",
+             vs->vserver_config->vserver_name);
+
+      rh_task_init(ms, vs); 
+      vs->vserver_config->init_flag = VS_DONE;
+    } else if (vs->vserver_config->init_flag == VS_RELOAD) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Config reload",
+             vs->vserver_config->vserver_name);
+
+      rh_task_cleanup(ms, vs);
+
+      if (vs->dummy_config != NULL) {
+        cleanup_vserver_config(vs->vserver_config);
+        memcpy(vs->vserver_config, vs->dummy_config, 
+          sizeof(struct rahunas_vserver_config));
+      }
+
+      vs->vserver_config->init_flag = VS_RELOAD;
+      rh_task_init(ms, vs); 
+      vs->vserver_config->init_flag = VS_DONE;
+    } else if (vs->vserver_config->init_flag == VS_RESET) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Config reset",
+             vs->vserver_config->vserver_name);
+
+      rh_task_cleanup(ms, vs);
+
+      if (vs->dummy_config != NULL) {
+        cleanup_vserver_config(vs->vserver_config);
+        memcpy(vs->vserver_config, vs->dummy_config, 
+          sizeof(struct rahunas_vserver_config));
+        rh_free(&vs->dummy_config);
+      }
+
+      vs->vserver_config->init_flag = VS_INIT;
+    } else {
+      /* Prevent infinite loop */
+      vs->vserver_config->init_flag = VS_DONE;
+    }
+  } 
+}
+
+
+void vserver_unused_cleanup(struct main_server *ms)
+{
+  GList *vserver_list = ms->vserver_list;
+  GList *runner = g_list_first(vserver_list);
+  struct vserver *lvserver = NULL;
+
+  while (runner != NULL) {
+    lvserver = (struct vserver *)runner->data;
+    if (lvserver->vserver_config->init_flag == VS_NONE) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Config removed",
+             lvserver->vserver_config->vserver_name);
+      rh_task_cleanup(ms, lvserver);
+      unregister_vserver(ms, lvserver->vserver_config->vserver_id);
+
+      ms->vserver_list = g_list_delete_link(ms->vserver_list, runner);
+      runner = g_list_first(ms->vserver_list);
+    } else {
+      runner = g_list_next(runner);
+    }
+  }
+  
+  return 0;
+}
index be825c9..af86e2d 100644 (file)
@@ -11,6 +11,7 @@
 
 struct vserver {
   struct rahunas_vserver_config *vserver_config;
+  struct rahunas_vserver_config *dummy_config;
   struct rahunas_map *v_map;
   struct set *v_set;
 };
@@ -20,9 +21,10 @@ struct main_server {
   GList *vserver_list;
   GList *task_list;
   int log_fd;
+  int polling_blocked;
 };
 
-int vserver_exists(GList *vserver_list, int vserver_id, 
+struct vserver *vserver_exists(GList *vserver_list, int vserver_id, 
                    const char *vserver_name);
 struct vserver *vserver_get_by_id(struct main_server *ms, int search_id);
 int vserver_cleanup(struct vserver *vs);
@@ -31,6 +33,8 @@ int walk_through_vserver(int (*callback)(void *, void *), struct main_server *ms
 int register_vserver(struct main_server *ms, const char *vserver_cfg_file);
 int unregister_vserver(struct main_server *ms, int vserver_id);
 int unregister_vserver_all(struct main_server *ms);
-
+void vserver_init_done(struct main_server *ms, struct vserver *vs);
+void vserver_reload(struct main_server *ms, struct vserver *vs);
+void vserver_unused_cleanup(struct main_server *ms);
 
 #endif // __RH_SERVER_H
index bb59568..629ae23 100644 (file)
@@ -282,6 +282,9 @@ static void init (struct vserver *vs)
   struct dbset_row *row;
   char select_cmd[256];
 
+  if (vs->vserver_config->init_flag == VS_RELOAD)
+    return;
+
   logmsg(RH_LOG_NORMAL, "[%s] Task DBSET initialize..",
          vs->vserver_config->vserver_name);  
 
index 79279a6..e890d17 100644 (file)
@@ -61,6 +61,9 @@ static int stopservice  ()
 /* Initialize */
 static void init (struct vserver *vs)
 {
+  if (vs->vserver_config->init_flag == VS_RELOAD)
+    return;
+
   vs->v_set = set_adt_get(vs->vserver_config->vserver_name);
   logmsg(RH_LOG_NORMAL, "[%s] Task IPSET initialize..",
          vs->vserver_config->vserver_name);  
@@ -76,6 +79,9 @@ static void init (struct vserver *vs)
 /* Cleanup */
 static void cleanup (struct vserver *vs)
 {
+  if (vs->vserver_config->init_flag == VS_RELOAD)
+    return;
+
   logmsg(RH_LOG_NORMAL, "[%s] Task IPSET cleanup..",
          vs->vserver_config->vserver_name);  
 
index adaaf28..26737c4 100644 (file)
@@ -29,7 +29,7 @@ int iptables_exec(struct vserver *vs, char *const args[])
   int ret = 0;
   int fd = 0;
   int i = 0;
-  char *env[21];
+  char *env[22];
 
   env[0]  = g_strdup("ENV_OVERRIDE=yes");
   env[1]  = g_strdup_printf("SETNAME=%s", vs->vserver_config->vserver_name);
@@ -54,7 +54,10 @@ int iptables_exec(struct vserver *vs, char *const args[])
                             vs->vserver_config->vserver_ports_allow);
   env[19] = g_strdup_printf("VSERVER_PORTS_INTERCEPT=%s", 
                             vs->vserver_config->vserver_ports_intercept);
-  env[20] = (char *) 0;
+  env[20] = g_strdup_printf("KEEP_SET=%s", 
+                            vs->vserver_config->init_flag == VS_RELOAD ?
+                            "yes" : "no");
+  env[21] = (char *) 0;
 
   for (i = 0; i < 21; i++) {
     if (env[i] != NULL) 
@@ -155,6 +158,7 @@ static int cleanup (struct vserver *vs)
 {
   logmsg(RH_LOG_NORMAL, "[%s] Task IPTABLES cleanup..",
          vs->vserver_config->vserver_name);  
+
   iptables_stop(vs);
 }
 
index f2ea60a..a1028c6 100644 (file)
@@ -56,6 +56,9 @@ static void init (struct vserver *vs)
 {
   int size;
 
+  if (vs->vserver_config->init_flag == VS_RELOAD)
+    return;
+
   logmsg(RH_LOG_NORMAL, "[%s] Task MEMSET initialize..",
          vs->vserver_config->vserver_name);  
 
@@ -81,6 +84,9 @@ static void cleanup (struct vserver *vs)
   GList *deleting = NULL;
   struct rahunas_member *member = NULL;
 
+  if (vs->vserver_config->init_flag == VS_RELOAD)
+    return;
+
   logmsg(RH_LOG_NORMAL, "[%s] Task MEMSET cleanup..",
          vs->vserver_config->vserver_name);  
 
index 880bdf2..fadce63 100755 (executable)
@@ -653,7 +653,7 @@ restart() {
 
 start_config() {
   test ! -f $RUNDIR/$SETNAME || return 0
-  add_set
+  test "$KEEP_SET" = "yes" || add_set
   new_chains
   rules
   touch $RUNDIR/$SETNAME
@@ -680,7 +680,7 @@ start_config_file() {
 stop_config() {
   test -f $RUNDIR/$SETNAME || return 0
   cleanup
-  cleanup_set
+  test "$KEEP_SET" = "yes" || cleanup_set
   rm -f $RUNDIR/$SETNAME
   return 0
 }