mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-11 10:25:47 +02:00
feat(cluster_mgr): Improvements to cluster_mgr.py
(#3118)
Make sure attached node is in right mode Enable detaching nodes
This commit is contained in:
parent
3924fcad68
commit
6e6c91aeaf
1 changed files with 69 additions and 17 deletions
|
@ -12,6 +12,11 @@ To install: pip install -r requirements.txt
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def die_with_err(err):
|
||||||
|
print("!!!", err)
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
|
||||||
class Node:
|
class Node:
|
||||||
def __init__(self, host, port):
|
def __init__(self, host, port):
|
||||||
self.id = ""
|
self.id = ""
|
||||||
|
@ -166,8 +171,7 @@ def config_single_remote(args):
|
||||||
|
|
||||||
test = send_command(master.node, ["get", "x"], print_errors=False)
|
test = send_command(master.node, ["get", "x"], print_errors=False)
|
||||||
if type(test) is not Exception:
|
if type(test) is not Exception:
|
||||||
print("Node either not found or already configured")
|
die_with_err("Node either not found or already configured")
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
config = build_config_from_list([master])
|
config = build_config_from_list([master])
|
||||||
print(f"Pushing config:\n{config}\n")
|
print(f"Pushing config:\n{config}\n")
|
||||||
|
@ -204,33 +208,46 @@ def build_config_from_existing(args):
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
def find_node(config, host, port):
|
def find_master(config, host, port, die_if_not_found=True):
|
||||||
new_owner = None
|
new_owner = None
|
||||||
for shard in config:
|
for shard in config:
|
||||||
if shard["master"]["ip"] == host and shard["master"]["port"] == port:
|
if shard["master"]["ip"] == host and shard["master"]["port"] == port:
|
||||||
new_owner = shard
|
new_owner = shard
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
print(f"Can't find master with port {port} (hint: use flag --target_port).")
|
if new_owner == None and die_if_not_found:
|
||||||
exit(-1)
|
die_with_err(f"Can't find master (hint: use flag --target_host / --target_port).")
|
||||||
|
|
||||||
return new_owner
|
return new_owner
|
||||||
|
|
||||||
|
|
||||||
def attach(args):
|
def attach(args):
|
||||||
print(f"Attaching remote Dragonfly {args.attach_host}:{args.attach_port} to cluster")
|
print(f"Attaching remote Dragonfly {args.attach_host}:{args.attach_port} to cluster")
|
||||||
if args.attach_as_replica:
|
if args.attach_as_replica:
|
||||||
config = build_config_from_existing(args)
|
|
||||||
master_node = find_node(config, args.target_host, args.target_port)
|
|
||||||
|
|
||||||
newcomer = Node(args.attach_host, args.attach_port)
|
newcomer = Node(args.attach_host, args.attach_port)
|
||||||
|
replica_resp = send_command(newcomer, ["info", "replication"])
|
||||||
|
if replica_resp["role"] != "replica":
|
||||||
|
die_with_err("Node is not in replica mode")
|
||||||
|
if (
|
||||||
|
replica_resp["master_host"] != args.target_host
|
||||||
|
or replica_resp["master_port"] != args.target_port
|
||||||
|
):
|
||||||
|
die_with_err("Node is not a replica of target")
|
||||||
|
|
||||||
newcomer.update_id()
|
newcomer.update_id()
|
||||||
newcomer_node = build_node(newcomer)
|
newcomer_node = build_node(newcomer)
|
||||||
|
|
||||||
|
config = build_config_from_existing(args)
|
||||||
|
master_node = find_master(config, args.target_host, args.target_port)
|
||||||
|
|
||||||
master_node["replicas"].append(newcomer_node)
|
master_node["replicas"].append(newcomer_node)
|
||||||
print(f"Pushing config:\n{config}\n")
|
print(f"Pushing config:\n{config}\n")
|
||||||
push_config(config)
|
push_config(config)
|
||||||
else:
|
else:
|
||||||
newcomer = Master(args.attach_host, args.attach_port)
|
newcomer = Master(args.attach_host, args.attach_port)
|
||||||
|
replica_resp = send_command(newcomer.node, ["info", "replication"])
|
||||||
|
if replica_resp["role"] != "master":
|
||||||
|
die_with_err("Node is not in master mode")
|
||||||
newcomer.node.update_id()
|
newcomer.node.update_id()
|
||||||
|
|
||||||
newcomer_config = build_config_from_list([newcomer])
|
newcomer_config = build_config_from_list([newcomer])
|
||||||
|
@ -241,9 +258,34 @@ def attach(args):
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def detach(args):
|
||||||
|
print(f"Detaching remote Dragonfly {args.target_host}:{args.target_port} from cluster")
|
||||||
|
print(
|
||||||
|
"Important: detached node will not receive a new config! This means that the detached node will still 'think' that it belongs to the cluster"
|
||||||
|
)
|
||||||
|
config = build_config_from_existing(args)
|
||||||
|
node = find_master(config, args.target_host, args.target_port, die_if_not_found=False)
|
||||||
|
if node == None:
|
||||||
|
found = False
|
||||||
|
for master in config:
|
||||||
|
for replica in master["replicas"]:
|
||||||
|
if replica["ip"] == args.target_host and replica["port"] == args.target_port:
|
||||||
|
master["replicas"].remove(replica)
|
||||||
|
found = True
|
||||||
|
if not found:
|
||||||
|
die_with_err("Can't find target node")
|
||||||
|
else:
|
||||||
|
if len(node["slot_ranges"]) != 0:
|
||||||
|
die_with_err("Can't detach a master with assigned slots")
|
||||||
|
if len(node["replicas"]) != 0:
|
||||||
|
die_with_err("Can't detach a master with replicas")
|
||||||
|
config = [m for m in config if m != node]
|
||||||
|
push_config(config)
|
||||||
|
|
||||||
|
|
||||||
def move(args):
|
def move(args):
|
||||||
config = build_config_from_existing(args)
|
config = build_config_from_existing(args)
|
||||||
new_owner = find_node(config, args.target_host, args.target_port)
|
new_owner = find_master(config, args.target_host, args.target_port)
|
||||||
|
|
||||||
def remove_slot(slot, from_range, from_shard):
|
def remove_slot(slot, from_range, from_shard):
|
||||||
if from_range["start"] == slot:
|
if from_range["start"] == slot:
|
||||||
|
@ -320,7 +362,7 @@ def move(args):
|
||||||
|
|
||||||
def migrate(args):
|
def migrate(args):
|
||||||
config = build_config_from_existing(args)
|
config = build_config_from_existing(args)
|
||||||
target = find_node(config, args.target_host, args.target_port)
|
target = find_master(config, args.target_host, args.target_port)
|
||||||
target_node = Node(target["master"]["ip"], target["master"]["port"])
|
target_node = Node(target["master"]["ip"], target["master"]["port"])
|
||||||
target_node.update_id()
|
target_node.update_id()
|
||||||
|
|
||||||
|
@ -333,8 +375,7 @@ def migrate(args):
|
||||||
source = node
|
source = node
|
||||||
break
|
break
|
||||||
if source == None:
|
if source == None:
|
||||||
print("Unsupported slot range migration (currently only 1-node migration supported)")
|
die_with_err("Unsupported slot range migration (currently only 1-node migration supported)")
|
||||||
exit(-1)
|
|
||||||
source_node = Node(source["master"]["ip"], source["master"]["port"])
|
source_node = Node(source["master"]["ip"], source["master"]["port"])
|
||||||
source_node.update_id()
|
source_node.update_id()
|
||||||
|
|
||||||
|
@ -410,20 +451,31 @@ This will connect to localhost:6379 by default. Override with `--target_host` an
|
||||||
Attach an existing Dragonfly server to an existing cluster (owning no slots):
|
Attach an existing Dragonfly server to an existing cluster (owning no slots):
|
||||||
./cluster_mgr.py --action=attach --attach_host=HOST --attach_port=PORT
|
./cluster_mgr.py --action=attach --attach_host=HOST --attach_port=PORT
|
||||||
This will connect to existing cluster present at localhost:6379 by default. Override with
|
This will connect to existing cluster present at localhost:6379 by default. Override with
|
||||||
`--target_host` and `--target_port`
|
`--target_host` and `--target_port`.
|
||||||
|
To attach node as a replica - use --attach_as_replica=True. In such case, the node will be a
|
||||||
|
replica of --target_host/--target_port.
|
||||||
|
|
||||||
To set up a new cluster - start the servers and then use
|
To set up a new cluster - start the servers and then use
|
||||||
./cluster_mgr.py --action=config_single_remote ...
|
./cluster_mgr.py --action=config_single_remote ...
|
||||||
./cluster_mgr.py --action=attach ...
|
./cluster_mgr.py --action=attach ...
|
||||||
And repeat `--action=attach` for all servers.
|
And repeat `--action=attach` for all servers.
|
||||||
Afterwards, distribute the slots between the servers as desired with `--action=move` or
|
Afterwards, distribute the slots between the servers as desired with `--action=move` or
|
||||||
`--action=migrate`
|
`--action=migrate`.
|
||||||
|
|
||||||
|
To detach (remove) a node from the cluster:
|
||||||
|
./cluster_mgr.py --action=detach --target_host=X --target_port=X
|
||||||
|
Notes:
|
||||||
|
- If the node is a master, it must not have any slots assigned to it.
|
||||||
|
- The node will not be notified that it's no longer in a cluster. It's a good idea to shut it down
|
||||||
|
after detaching it from the cluster.
|
||||||
|
|
||||||
Connect to cluster and move slots 10-20 to target:
|
Connect to cluster and move slots 10-20 to target:
|
||||||
./cluster_mgr.py --action=move --slot_start=10 --slot_end=20 --target_host=X --target_port=X
|
./cluster_mgr.py --action=move --slot_start=10 --slot_end=20 --target_host=X --target_port=X
|
||||||
|
WARNING: This will NOT migrate existing data, i.e. data in slots 10-20 will be erased.
|
||||||
|
|
||||||
Migrate slots 10-20 to target:
|
Migrate slots 10-20 to target:
|
||||||
./cluster_mgr.py --action=migrate --slot_start=10 --slot_end=20 --target_host=X --target_port=X
|
./cluster_mgr.py --action=migrate --slot_start=10 --slot_end=20 --target_host=X --target_port=X
|
||||||
|
Unlike --action=move above, this will migrate the data to the new owner.
|
||||||
|
|
||||||
Connect to cluster and shutdown all nodes:
|
Connect to cluster and shutdown all nodes:
|
||||||
./cluster_mgr.py --action=shutdown
|
./cluster_mgr.py --action=shutdown
|
||||||
|
@ -471,6 +523,7 @@ WARNING: Be careful! This will close all Dragonfly servers connected to the clus
|
||||||
shutdown,
|
shutdown,
|
||||||
config_single_remote,
|
config_single_remote,
|
||||||
attach,
|
attach,
|
||||||
|
detach,
|
||||||
move,
|
move,
|
||||||
print_config,
|
print_config,
|
||||||
migrate,
|
migrate,
|
||||||
|
@ -481,8 +534,7 @@ WARNING: Be careful! This will close all Dragonfly servers connected to the clus
|
||||||
if action:
|
if action:
|
||||||
action(args)
|
action(args)
|
||||||
else:
|
else:
|
||||||
print(f'Error - unknown action "{args.action}". See --help')
|
die_with_err(f'Error - unknown action "{args.action}". See --help')
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue