[SCM] CTDB repository - branch master updated - ctdb-2.0-28-g1a5410e
Amitay Isaacs
amitay at samba.org
Sun Jan 6 21:16:37 MST 2013
The branch, master has been updated
via 1a5410e8349cdb96fdc51aa5ecd4f5734f6798a5 (commit)
via 8164d9b29bf9080ccc76b1305fb6c07f1ed61d55 (commit)
via cc1a3ae911d3fee8b87fda5de5ab6d9499d7510a (commit)
from b849fb4923d6a34141fe19006a974de81508ceda (commit)
http://gitweb.samba.org/?p=ctdb.git;a=shortlog;h=master
- Log -----------------------------------------------------------------
commit 1a5410e8349cdb96fdc51aa5ecd4f5734f6798a5
Author: Martin Schwenke <martin at meltin.net>
Date: Fri Nov 30 16:38:08 2012 +1100
tests: new simple integration test for delip interface garbage collection
Signed-off-by: Martin Schwenke <martin at meltin.net>
commit 8164d9b29bf9080ccc76b1305fb6c07f1ed61d55
Author: Martin Schwenke <martin at meltin.net>
Date: Fri Nov 30 16:37:28 2012 +1100
tests: new function ip2ipmask() for integration testing
Signed-off-by: Martin Schwenke <martin at meltin.net>
commit cc1a3ae911d3fee8b87fda5de5ab6d9499d7510a
Author: Martin Schwenke <martin at meltin.net>
Date: Fri Nov 23 20:09:07 2012 +1100
ctdbd: Clean up orphaned interfaces when an IP is deleted
Add a new function ctdb_remove_orphaned_ifaces() and call it in
ctdb_control_del_public_address().
ctdb_remove_orphaned_ifaces() uses a naive implementation that does
things in a very obvious way. There are many ways to improve the
performance - some are mentioned in a comment in the code. However, I
doubt that this will be a bottleneck even with a large number of
public IPs. Running the eventscript is likely to outweigh the cost of
this cleanup.
Signed-off-by: Martin Schwenke <martin at meltin.net>
Pair-programmed-with: Amitay Isaacs <amitay at gmail.com>
-----------------------------------------------------------------------
Summary of changes:
server/ctdb_takeover.c | 76 +++++++++++++++++++++++++++++++++++--
tests/scripts/integration.bash | 7 +++
tests/simple/20_delip_iface_gc.sh | 62 ++++++++++++++++++++++++++++++
3 files changed, 141 insertions(+), 4 deletions(-)
create mode 100755 tests/simple/20_delip_iface_gc.sh
Changeset truncated at 500 lines:
diff --git a/server/ctdb_takeover.c b/server/ctdb_takeover.c
index 5345251..df543fe 100644
--- a/server/ctdb_takeover.c
+++ b/server/ctdb_takeover.c
@@ -85,6 +85,74 @@ static int ctdb_add_local_iface(struct ctdb_context *ctdb, const char *iface)
return 0;
}
+static bool vnn_has_interface_with_name(struct ctdb_vnn *vnn,
+ const char *name)
+{
+ int n;
+
+ for (n = 0; vnn->ifaces[n] != NULL; n++) {
+ if (strcmp(name, vnn->ifaces[n]) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* If any interfaces now have no possible IPs then delete them. This
+ * implementation is naive (i.e. simple) rather than clever
+ * (i.e. complex). Given that this is run on delip and that operation
+ * is rare, this doesn't need to be efficient - it needs to be
+ * foolproof. One alternative is reference counting, where the logic
+ * is distributed and can, therefore, be broken in multiple places.
+ * Another alternative is to build a red-black tree of interfaces that
+ * can have addresses (by walking ctdb->vnn and ctdb->single_ip_vnn
+ * once) and then walking ctdb->ifaces once and deleting those not in
+ * the tree. Let's go to one of those if the naive implementation
+ * causes problems... :-)
+ */
+static void ctdb_remove_orphaned_ifaces(struct ctdb_context *ctdb,
+ struct ctdb_vnn *vnn,
+ TALLOC_CTX *mem_ctx)
+{
+ struct ctdb_iface *i;
+
+ /* For each interface, check if there's an IP using it. */
+ for(i=ctdb->ifaces; i; i=i->next) {
+ struct ctdb_vnn *tv;
+ bool found;
+
+ /* Only consider interfaces named in the given VNN. */
+ if (!vnn_has_interface_with_name(vnn, i->name)) {
+ continue;
+ }
+
+ /* Is the "single IP" on this interface? */
+ if ((ctdb->single_ip_vnn != NULL) &&
+ (ctdb->single_ip_vnn->ifaces[0] != NULL) &&
+ (strcmp(i->name, ctdb->single_ip_vnn->ifaces[0]) == 0)) {
+ /* Found, next interface please... */
+ continue;
+ }
+ /* Search for a vnn with this interface. */
+ found = false;
+ for (tv=ctdb->vnn; tv; tv=tv->next) {
+ if (vnn_has_interface_with_name(tv, i->name)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* None of the VNNs are using this interface. */
+ DLIST_REMOVE(ctdb->ifaces, i);
+ /* Caller will free mem_ctx when convenient. */
+ talloc_steal(mem_ctx, i);
+ }
+ }
+}
+
+
static struct ctdb_iface *ctdb_find_iface(struct ctdb_context *ctdb,
const char *iface)
{
@@ -3665,20 +3733,20 @@ int32_t ctdb_control_del_public_address(struct ctdb_context *ctdb, TDB_DATA inda
/* walk over all public addresses until we find a match */
for (vnn=ctdb->vnn;vnn;vnn=vnn->next) {
if (ctdb_same_ip(&vnn->public_address, &pub->addr)) {
- TALLOC_CTX *mem_ctx;
+ TALLOC_CTX *mem_ctx = talloc_new(ctdb);
DLIST_REMOVE(ctdb->vnn, vnn);
+ talloc_steal(mem_ctx, vnn);
+ ctdb_remove_orphaned_ifaces(ctdb, vnn, mem_ctx);
if (vnn->pnn != ctdb->pnn) {
if (vnn->iface != NULL) {
ctdb_vnn_unassign_iface(ctdb, vnn);
}
- talloc_free(vnn);
+ talloc_free(mem_ctx);
return 0;
}
vnn->pnn = -1;
- mem_ctx = talloc_new(ctdb);
- talloc_steal(mem_ctx, vnn);
ret = ctdb_event_script_callback(ctdb,
mem_ctx, delete_ip_callback, mem_ctx,
false,
diff --git a/tests/scripts/integration.bash b/tests/scripts/integration.bash
index 8813499..07e764e 100644
--- a/tests/scripts/integration.bash
+++ b/tests/scripts/integration.bash
@@ -494,6 +494,13 @@ wait_until_node_has_some_ips ()
wait_until 60 node_has_some_ips "$@"
}
+ip2ipmask ()
+{
+ _ip="$1"
+
+ ip addr show to "$_ip" | awk '$1 == "inet" { print $2 }'
+}
+
#######################################
daemons_stop ()
diff --git a/tests/simple/20_delip_iface_gc.sh b/tests/simple/20_delip_iface_gc.sh
new file mode 100755
index 0000000..bc43567
--- /dev/null
+++ b/tests/simple/20_delip_iface_gc.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+
+test_info()
+{
+ cat <<EOF
+Verify that an interface is deleted when all IPs on it are deleted.
+EOF
+}
+
+. "${TEST_SCRIPTS_DIR}/integration.bash"
+
+ctdb_test_init "$@"
+
+set -e
+
+cluster_is_healthy
+
+# Reset configuration
+ctdb_restart_when_done
+
+echo "Getting public IPs information..."
+try_command_on_node -v any "$CTDB ip -v -n all -Y | tail -n +2"
+ip_info="$out"
+
+# Select the first node and find out its interfaces
+test_node=$(awk -F: 'NR == 1 { print $3}' <<<"$ip_info")
+ifaces=$(awk -F: -v tn=$test_node '$3 == tn { print $6 }' <<<"$ip_info" | sed 's@, @ @g' | xargs -n 1 | sort -u)
+echo "Selected test node ${test_node} with interfaces: ${ifaces}"
+
+# Delete all IPs on each interface... deleting IPs from one interface
+# can cause other interfaces to disappear, so we need to be careful...
+for i in $ifaces ; do
+ try_command_on_node $test_node "$CTDB ifaces -Y"
+ info=$(awk -F: -v iface="$i" '$2 == iface { print $0 }' <<<"$out")
+
+ if [ -z "$info" ] ; then
+ echo "Interface ${i} missing... assuming already deleted!"
+ continue
+ fi
+
+ echo "Deleting IPs on interface ${i}, with this information:"
+ echo " $info"
+
+ try_command_on_node $test_node "$CTDB ip -v -Y | tail -n +2"
+ awk -F: -v i="$i" \
+ '$6 == i { print $2 }' <<<"$out" |
+ while read ip ; do
+ echo " $ip"
+ try_command_on_node $test_node "$CTDB delip $ip"
+ done
+
+ try_command_on_node $test_node "$CTDB ifaces -Y"
+ info=$(awk -F: -v iface="$i" '$2 == iface { print $0 }' <<<"$out")
+
+ if [ -z "$info" ] ; then
+ echo "GOOD: Interface ${i} has been garbage collected"
+ else
+ echo "BAD: Interface ${i} still exists"
+ echo "$out"
+ exit 1
+ fi
+done
--
CTDB repository
More information about the samba-cvs
mailing list