when adding a new public ip address to a running node using the 'ctdb addip' command,
authorRonnie Sahlberg <sahlberg@samba.org>
Wed, 23 Apr 2008 11:05:36 +0000 (21:05 +1000)
committerRonnie Sahlberg <sahlberg@samba.org>
Wed, 23 Apr 2008 11:05:36 +0000 (21:05 +1000)
If no other node is hosting this public ip at the moment, then assign it immediately to the current node.

(This used to be ctdb commit a63825e32658b36e0964584758b9a276c18056b8)

ctdb/tools/ctdb.c

index 2a3228bc054c58b98d0e9616bc0c85ff9047ea3a..6e944175722f4b8fabb6e103a7628982f7264fb7 100644 (file)
@@ -417,6 +417,40 @@ static int control_get_tickles(struct ctdb_context *ctdb, int argc, const char *
        return 0;
 }
 
+/* send a release ip to all nodes */
+static int control_send_release(struct ctdb_context *ctdb, uint32_t pnn,
+struct sockaddr_in *sin)
+{
+       int ret;
+       struct ctdb_public_ip pip;
+       TDB_DATA data;
+       struct ctdb_node_map *nodemap=NULL;
+
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
+               return ret;
+       }
+
+       /* send a moveip message to the recovery master */
+       pip.pnn = pnn;
+       pip.sin.sin_family = AF_INET;
+       pip.sin.sin_addr   = sin->sin_addr;
+       data.dsize = sizeof(pip);
+       data.dptr = (unsigned char *)&pip;
+
+
+       /* send release ip to all nodes */
+       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_RELEASE_IP,
+                       list_of_active_nodes(ctdb, nodemap, ctdb, true),
+                       TIMELIMIT(), false, data) != 0) {
+               DEBUG(DEBUG_ERR, (__location__ " Unable to send 'ReleaseIP' to all nodes.\n"));
+               return -1;
+       }
+
+       return 0;
+}
+
 /*
   move/failover an ip address to a specific node
  */
@@ -426,9 +460,6 @@ static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv
        struct sockaddr_in ip;
        uint32_t value;
        struct ctdb_all_public_ips *ips;
-       struct ctdb_public_ip pip;
-       TDB_DATA data;
-       struct ctdb_node_map *nodemap=NULL;
        int i, ret;
 
        if (argc < 2) {
@@ -442,12 +473,6 @@ static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv
        }
 
 
-       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, ctdb, &nodemap);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to get nodemap from local node\n"));
-               return ret;
-       }
-
        if (sscanf(argv[1], "%u", &pnn) != 1) {
                DEBUG(DEBUG_ERR, ("Badly formed pnn\n"));
                return -1;
@@ -496,47 +521,128 @@ static int control_moveip(struct ctdb_context *ctdb, int argc, const char **argv
                return -1;
        }
 
-       /* send a moveip message to the recovery master */
-       pip.pnn = pnn;
-       pip.sin.sin_family = AF_INET;
-       pip.sin.sin_addr   = ips->ips[i].sin.sin_addr;
-       data.dsize = sizeof(pip);
-       data.dptr = (unsigned char *)&pip;
+       ret = control_send_release(ctdb, pnn, &ips->ips[i].sin);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Failed to send 'change ip' to all nodes\n"));;
+               return -1;
+       }
 
+       return 0;
+}
 
-       /* send release ip to all nodes */
-       if (ctdb_client_async_control(ctdb, CTDB_CONTROL_RELEASE_IP,
-                       list_of_active_nodes(ctdb, nodemap, ctdb, true),
-                       TIMELIMIT(), false, data) != 0) {
-               DEBUG(DEBUG_ERR, (__location__ " Unable to send 'ReleaseIP' to all nodes.\n"));
-               return -1;
+struct node_ip {
+       uint32_t pnn;
+       struct sockaddr_in sin;
+};
+
+void getips_store_callback(void *param, void *data)
+{
+       struct node_ip *node_ip = (struct node_ip *)data;
+       struct ctdb_all_public_ips *ips = param;
+       int i;
+
+       i = ips->num++;
+       ips->ips[i].pnn = node_ip->pnn;
+       ips->ips[i].sin = node_ip->sin;
+}
+
+void getips_count_callback(void *param, void *data)
+{
+       uint32_t *count = param;
+
+       (*count)++;
+}
+
+static int
+control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_all_public_ips **ips)
+{
+       struct ctdb_all_public_ips *tmp_ips;
+       struct ctdb_node_map *nodemap=NULL;
+       trbt_tree_t *tree;
+       int i, j, len, ret;
+       uint32_t count;
+
+       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
+               return ret;
+       }
+
+       tree = trbt_create(tmp_ctx, 0);
+
+       for(i=0;i<nodemap->num;i++){
+               if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
+                       continue;
+               }
+
+               /* read the public ip list from this node */
+               ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &tmp_ips);
+               if (ret != 0) {
+                       DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn));
+                       return -1;
+               }
+       
+               for (j=0; j<tmp_ips->num;j++) {
+                       struct node_ip *node_ip;
+
+                       node_ip = talloc(tmp_ctx, struct node_ip);
+                       node_ip->pnn = tmp_ips->ips[j].pnn;
+                       node_ip->sin = tmp_ips->ips[j].sin;
+
+                       trbt_insert32(tree, tmp_ips->ips[j].sin.sin_addr.s_addr, node_ip);
+               }
+               talloc_free(tmp_ips);
        }
 
+       /* traverse */
+       count = 0;
+       trbt_traversearray32(tree, 1, getips_count_callback, &count);
+
+       len = offsetof(struct ctdb_all_public_ips, ips) + 
+               count*sizeof(struct ctdb_public_ip);
+       tmp_ips = talloc_zero_size(tmp_ctx, len);
+       trbt_traversearray32(tree, 1, getips_store_callback, tmp_ips);
+
+       *ips = tmp_ips;
+
        return 0;
 }
 
+
 /*
   add a public ip address to a node
  */
 static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
 {
-       int ret;
+       int i, ret;
        int len;
        unsigned mask;
        struct sockaddr_in addr;
        struct ctdb_control_ip_iface *pub;
+       TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
+       struct ctdb_all_public_ips *ips;
 
        if (argc != 2) {
+               talloc_free(tmp_ctx);
                usage();
        }
 
        if (!parse_ip_mask(argv[0], &addr, &mask)) {
                DEBUG(DEBUG_ERR, ("Badly formed ip/mask : %s\n", argv[0]));
+               talloc_free(tmp_ctx);
                return -1;
        }
 
+       ret = control_get_all_public_ips(ctdb, tmp_ctx, &ips);
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Unable to get public ip list from cluster\n"));
+               talloc_free(tmp_ctx);
+               return ret;
+       }
+
+
        len = offsetof(struct ctdb_control_ip_iface, iface) + strlen(argv[1]) + 1;
-       pub = talloc_size(ctdb, len); 
+       pub = talloc_size(tmp_ctx, len); 
        CTDB_NO_MEMORY(ctdb, pub);
 
        pub->sin   = addr;
@@ -547,9 +653,32 @@ static int control_addip(struct ctdb_context *ctdb, int argc, const char **argv)
        ret = ctdb_ctrl_add_public_ip(ctdb, TIMELIMIT(), options.pnn, pub);
        if (ret != 0) {
                DEBUG(DEBUG_ERR, ("Unable to add public ip to node %u\n", options.pnn));
+               talloc_free(tmp_ctx);
                return ret;
        }
 
+
+       /* check if some other node is already serving this ip, if not,
+        * we will claim it
+        */
+       for (i=0;i<ips->num;i++) {
+               if (ctdb_same_ip(&addr, &ips->ips[i].sin)) {
+                       break;
+               }
+       }
+       /* no one has this ip so we claim it */
+       if (i == ips->num) {
+               ret = control_send_release(ctdb, options.pnn, &addr);
+       } else {
+               ret = control_send_release(ctdb, ips->ips[i].pnn, &addr);
+       }
+
+       if (ret != 0) {
+               DEBUG(DEBUG_ERR, ("Failed to send 'change ip' to all nodes\n"));
+               return -1;
+       }
+
+       talloc_free(tmp_ctx);
        return 0;
 }
 
@@ -786,84 +915,6 @@ static int tickle_tcp(struct ctdb_context *ctdb, int argc, const char **argv)
 }
 
 
-struct node_ip {
-       uint32_t pnn;
-       struct sockaddr_in sin;
-};
-
-void getips_store_callback(void *param, void *data)
-{
-       struct node_ip *node_ip = (struct node_ip *)data;
-       struct ctdb_all_public_ips *ips = param;
-       int i;
-
-       i = ips->num++;
-       ips->ips[i].pnn = node_ip->pnn;
-       ips->ips[i].sin = node_ip->sin;
-}
-
-void getips_count_callback(void *param, void *data)
-{
-       uint32_t *count = param;
-
-       (*count)++;
-}
-
-static int
-control_get_all_public_ips(struct ctdb_context *ctdb, TALLOC_CTX *tmp_ctx, struct ctdb_all_public_ips **ips)
-{
-       struct ctdb_all_public_ips *tmp_ips;
-       struct ctdb_node_map *nodemap=NULL;
-       trbt_tree_t *tree;
-       int i, j, len, ret;
-       uint32_t count;
-
-       ret = ctdb_ctrl_getnodemap(ctdb, TIMELIMIT(), CTDB_CURRENT_NODE, tmp_ctx, &nodemap);
-       if (ret != 0) {
-               DEBUG(DEBUG_ERR, ("Unable to get nodemap from node %u\n", options.pnn));
-               return ret;
-       }
-
-       tree = trbt_create(tmp_ctx, 0);
-
-       for(i=0;i<nodemap->num;i++){
-               if (nodemap->nodes[i].flags & NODE_FLAGS_DISCONNECTED) {
-                       continue;
-               }
-
-               /* read the public ip list from this node */
-               ret = ctdb_ctrl_get_public_ips(ctdb, TIMELIMIT(), nodemap->nodes[i].pnn, tmp_ctx, &tmp_ips);
-               if (ret != 0) {
-                       DEBUG(DEBUG_ERR, ("Unable to get public ip list from node %u\n", nodemap->nodes[i].pnn));
-                       return -1;
-               }
-       
-               for (j=0; j<tmp_ips->num;j++) {
-                       struct node_ip *node_ip;
-
-                       node_ip = talloc(tmp_ctx, struct node_ip);
-                       node_ip->pnn = tmp_ips->ips[j].pnn;
-                       node_ip->sin = tmp_ips->ips[j].sin;
-
-                       trbt_insert32(tree, tmp_ips->ips[j].sin.sin_addr.s_addr, node_ip);
-               }
-               talloc_free(tmp_ips);
-       }
-
-       /* traverse */
-       count = 0;
-       trbt_traversearray32(tree, 1, getips_count_callback, &count);
-
-       len = offsetof(struct ctdb_all_public_ips, ips) + 
-               count*sizeof(struct ctdb_public_ip);
-       tmp_ips = talloc_zero_size(tmp_ctx, len);
-       trbt_traversearray32(tree, 1, getips_store_callback, tmp_ips);
-
-       *ips = tmp_ips;
-
-       return 0;
-}
-
 /*
   display public ip status
  */
@@ -1707,7 +1758,7 @@ static const struct {
        { "reloadnodes",     control_reload_nodes_file,         false, "reload the nodes file and restart the transport on all nodes"},
        { "getreclock",      control_getreclock,        false,  "get the path to the reclock file" },
        { "moveip",          control_moveip,            false, "move/failover an ip address to another node", "<ip> <node>"},
-       { "addip",           control_addip,             false, "add a ip address to a node", "<ip/mask> <iface>"},
+       { "addip",           control_addip,             true, "add a ip address to a node", "<ip/mask> <iface>"},
        { "delip",           control_delip,             false, "delete an ip address from a node", "<ip>"},
        { "eventscript",     control_eventscript,       true, "run the eventscript with the given parameters on a node", "<arguments>"},
 };