def launch(args): """Main entrypoint of Odin CLI""" pl_slice = conf.get_slice() node_count = conf.get_number_of_nodes() byz_count = conf.get_number_of_byzantine() if not args.reuse_hosts: logger.info("Fetching nodes for slice") nodes = api.get_nodes_for_slice(pl_slice, node_count) else: logger.info("Re-using nodes from hosts.txt") if not io.exists("hosts.txt"): logger.error("Can't re-use hosts from non-existing hosts.txt") sys.exit(1) # parse hosts file with open("hosts.txt") as f: lines = [x.rstrip() for x in f.readlines()] nodes = [{ "id": l.split(",")[0], "hostname": l.split(",")[1] } for l in lines] regular_nodes = nodes[byz_count:] byz_nodes = nodes[:byz_count] if io.exists(conf.get_heimdall_sd_path()): generate_heimdall_sd(byz_nodes + regular_nodes, args.scale) setup_heimdall() deploy(byz_nodes, regular_nodes, args)
def cleanup(): """Helper function that kills all processes started by on PL hosts.""" user = conf.get_slice() with open("hosts.txt") as f: for l in f.readlines(): hostname = l.split(",")[1] run_command(hostname, f"pkill -u {user}")
def find_healthy_nodes(): """Helper function that can be used to find healthy nodes on PlanetLab.""" slc = conf.get_slice() old_nodes = api.get_node_ids_for_slice(slc) logger.info(f"Old nodes for {slc}: {old_nodes}") logger.info(f"Attaching all nodes to slice temporarily") all_nodes = api.get_all_nodes() node_ids = list(map(lambda n: n["node_id"], all_nodes)) api.set_nodes_for_slice(node_ids) count = api.get_node_ids_for_slice(slc) logger.info(f"{conf.get_slice()} node has {count} nodes attached [temp]") threads = [] logger.info(f"Checking {len(all_nodes)} nodes to see if they're healthy") for n in all_nodes: t = Thread(target=check_node, args=(n, )) t.start() threads.append(t) for t in threads: t.join() logger.info("All nodes checked, writing result files in etc/") with open("etc/healthy_nodes.txt", "w+") as f: for n in healthy_nodes: f.write(f"{n}\n") with open("etc/faulty_nodes.txt", "w+") as f: for n in faulty_nodes: f.write(f"{n}\n") logger.info(f"Healthy node discovery done!") api.set_nodes_for_slice(old_nodes) logger.info(f"Nodes for slice reset to {old_nodes}")
"""This module contains code related to connecting to/executing on hosts.""" from conf import conf from helpers import io import logging import subprocess logger = logging.getLogger(__name__) SSH_KEY_PATH = conf.get_ssh_key_path() SLICE = conf.get_slice() def get_log_file(hostname): """Returns the local log file for a given hostname.""" if not io.exists("./etc/logs"): io.create_dir("./etc/logs") return open(f"./etc/logs/{hostname}.log", "a") def transfer_files(hostname, files, target_dir, timeout=10): """Transfers a list of files to a host.""" logger.debug(f"Transferring files {files} to {hostname}:{target_dir}") log_file = get_log_file(hostname) for f in files: cmd_string = (f"scp -o StrictHostKeyChecking=no -o UserKnownHosts" + f"File=/dev/null -i {SSH_KEY_PATH} {f} " + f"{SLICE}@{hostname}:{target_dir}") try: process = subprocess.Popen(cmd_string.split(), stdout=log_file, stderr=log_file)
def add_all_nodes_to_slice(slice_name=conf.get_slice()): """Adds ALL nodes on PlanetLab to slice.""" nodes = get_all_nodes() nodes = list(map(lambda n: n["node_id"], nodes)) set_nodes_for_slice(nodes)
def set_nodes_for_slice(nodes, slice_name=conf.get_slice()): """Attaches the nodes {nodes} to {slice_name}.""" api_server.UpdateSlice(auth, slice_name, {"n.odes": nodes}) logger.info(f"Set nodes {nodes} for slice {slice_name}")