def iter_experiments(cls, *args, include_waiting=False, target=None, api=None, nodes_class=nodes.BaseNodes, node_class=nodes.BaseNode, **kwargs): if api is None: api = common.get_default_api() def _get_exp(exp_id): try: info = api.get_experiment_info(exp_id) except urllib.error.HTTPError as exc: raise ExperimentError(exc.reason) from exc nodes_ = nodes_class(node_list=info["nodes"], api=api, node_class=node_class) return cls(name=info["name"], nodes=nodes_, target=target, exp_id=exp_id, api=api, *args, **kwargs) try: exps = iotlabcli.experiment.get_active_experiments( api, running_only=not include_waiting ) except urllib.error.HTTPError as exc: raise ExperimentError(exc.reason) from exc for exp_id in exps.get("Running", []): yield _get_exp(exp_id) for exp_id in exps.get("Waiting", []): yield _get_exp(exp_id)
def __init__(self, name, nodes, *args, target=None, firmwares=None, exp_id=None, profiles=None, api=None, **kwargs): # pylint: disable=redefined-outer-name # nodes module is not used in this constructor, so it is safe to # redefine the name as a variable if (firmwares is not None) and \ (len(firmwares) > 1) and (len(nodes) != len(firmwares)): raise ExperimentError( "firmwares must be of length 1 or the multiplicity of nodes" ) if (profiles is not None) and \ (len(profiles) > 1) and (len(nodes) != len(profiles)): raise ExperimentError( "profiles must be of length 1 or the multiplicity of nodes" ) username, _ = iotlabcli.auth.get_user_credentials() self.name = name self.nodes = nodes self.firmwares = firmwares self.profiles = profiles self.username = username self.target = target self.target_args = args self.target_kwargs = kwargs if api is None: self.api = common.get_default_api() else: self.api = api self.exp_id = exp_id if self.is_scheduled(): self._check_experiment()
def __init__(self, filename, api=None): if api is None: self.api = common.get_default_api() else: self.api = api self.runners = [] self._file_handler = DescriptionFileHandler(filename) self.descs = {}
def __init__(self, dispatcher, desc, exp_id=None, api=None): if api is None: self.api = common.get_default_api() else: self.api = api self.dispatcher = dispatcher self.desc = desc self._build_simple_params(exp_id) self._init_nodes() self._init_firmwares() self._init_profiles() self.experiment = self._init_experiment()
def __init__(self, node_list=None, state=None, api=None, node_class=BaseNode): if node_list is None: node_list = [] self.state = state if api is None: self.api = common.get_default_api() else: self.api = api self.nodes = { args["network_address"]: node_class.from_dict(args, api=self.api) for args in self._fetch_all_nodes() if args["network_address"] in node_list } self.node_class = node_class self.iter_idx = -1
def construct_network(sink, iotlab_site=DEFAULT_IOTLAB_SITE, min_distance=MIN_DISTANCE, max_distance=MAX_DISTANCE, min_neighbors=MIN_NEIGHBORS, max_neighbors=MAX_NEIGHBORS, max_nodes=MAX_NODES, api=None): def _restrict_potential_neighbors(node_set, node, network): potential_neighbors = set(n for n in node_set.values() if _node_num(n) not in NODE_BLACKLIST[iotlab_site]) potential_neighbors.remove(node) # select nodes where # neigh is is within max_distance of node and # neigh is not already in network # neigh is further away than min_distance from all other nodes and # and there is no node in network that is within min_distance of neigh return [ neigh for neigh in potential_neighbors if (node.distance(neigh) < max_distance) and (neigh not in network) and ((neigh.distance(w) >= min_distance) for w in potential_neighbors - {neigh}) and not any((neigh.distance(x) < min_distance) for x in network) ] if sink in NODE_BLACKLIST[iotlab_site]: logging.warning("Sink {} in blacklist for site {}".format(sink, iotlab_site)) sink = "{}-{}".format(ARCHI_SHORT, sink) if api is None: api = get_default_api() # get all nodes that are alive and not booked from iotlab_site node_selection = SinkNetworkedNodes.all_nodes(iotlab_site, "Alive", ARCHI_FULL, api, sink=sink) if get_uri(iotlab_site, sink) not in node_selection: raise NetworkConstructionError("Sink {} is not 'Alive' (maybe booked " "by other experiment?)".format(sink)) result = SinkNetworkedNodes(iotlab_site, sink) sink = result[sink] # BFS from sink queue = Queue() visited = set([sink]) queue.put(sink) def _save_result(): draw_network(result, False, with_labels=True) plt.savefig(os.path.join(DATA_PATH, "{}_logic.svg".format(result)), dpi=150) plt.clf() draw_network(result, True, with_labels=True) plt.savefig(os.path.join(DATA_PATH, "{}_geo.svg".format(result)), dpi=150) result.save_edgelist( os.path.join(DATA_PATH, "{}.edgelist.gz".format(result)) ) plt.clf() while not queue.empty() and len(result) < max_nodes: node = queue.get() candidates = _restrict_potential_neighbors( node_selection.nodes, node_selection[node.uri], result ) if not candidates: continue if node == sink: # sink always has two neighbors num_neigh = 2 else: num_neigh = random.randint( min(min_neighbors, len(candidates)), min(max_neighbors, len(candidates)) ) neighbor_sample = random.sample(candidates, num_neigh) for neigh in neighbor_sample: if neigh not in visited: result.add_edge(node, neigh) if len(result) == max_nodes: _save_result() return result visited.add(neigh) queue.put(neigh) _save_result() return result
def main(): def existing_file(parser, arg): arg = str(arg) if not os.path.exists(arg): parser.error("The file {} does not exist!".format(arg)) else: return arg parser = argparse.ArgumentParser() parser.add_argument("-l", "--data-len", default=DEFAULT_DATA_LEN, type=int, help="Payload size of the UDP packets to sent " "(default: {})".format(DEFAULT_DATA_LEN)) parser.add_argument("-c", "--count", default=DEFAULT_COUNT, type=int, help="Number of UDP packets to send per source " "(default: {})".format(DEFAULT_COUNT)) parser.add_argument("-W", "--delay", default=DEFAULT_DELAY, type=int, help="Delay between the UDP packets sent " "(default: {})".format(DEFAULT_DELAY)) parser.add_argument("-d", "--duration", default=DEFAULT_DURATION, type=int, help="IoT-LAB experiment duration " "(default: {})".format(DEFAULT_DURATION)) parser.add_argument( "-S", "--iotlab-site", default=construct_network.DEFAULT_IOTLAB_SITE, help="IoT-LAB site to pick nodes from (default: {})".format( construct_network.DEFAULT_IOTLAB_SITE)) parser.add_argument("-f", "--edgelist-file", default=None, type=lambda t: existing_file(parser, t), help="NetworkX edge-list for the network (optional, " "if not provided `construct_network` will be " "run before experiment starts)") parser.add_argument("-i", "--exp-id", default=None, type=int, help="ID of a pre-existing IoT-LAB experiment " "(optional)") parser.add_argument("-r", "--reflash", action="store_true", help="When given with --exp-id: reflash nodes of " "IoT-LAB experiment instead of resetting it") parser.add_argument("-t", "--tmux-target", default=None, help="TMUX target for experiment control " "(default: the IoT-LAB experiment name)") parser.add_argument("-s", "--sniff", action="store_true", help="Activate sniffer profile for all participating " "nodes") parser.add_argument("-v", "--verbose", action="store_true", help="Increase output verbosity (logging level DEBUG)") parser.add_argument("--channel", default=DEFAULT_CHANNEL, type=int, help="Channel (for sniffer profile) " "(default: {})".format(DEFAULT_CHANNEL)) parser.add_argument("--run-duration", type=int, default=None, help="Duration of a single run in the experiment in " "seconds (default: calculated from --delay and " "--count)") parser.add_argument("sink", type=int, help="Number of the M3 sink node within the network") parser.add_argument("mode", default=DEFAULT_MODE, choices=MODES, nargs="?", help="Experiment mode (reass: hop-wise reassembly, " "fwd: fragment forwarding)") args = parser.parse_args() logging.basicConfig(format='%(asctime)s:%(levelname)s: %(message)s', level=logging.DEBUG if args.verbose else logging.INFO) api = get_default_api() if args.edgelist_file is None: network = construct_network.construct_network(args.sink, args.iotlab_site, api=api) else: network = load_network(args.sink, args.edgelist_file, args.iotlab_site) start_experiment(network, duration=args.duration, exp_id=args.exp_id, channel=args.channel, reflash=args.reflash, tmux_target=args.tmux_target, mode=args.mode, data_len=args.data_len, count=args.count, delay=args.delay, run_duration=args.run_duration, sniff=args.sniff, api=api)
def start_experiment(network, name=None, duration=DEFAULT_DURATION, sink_firmware_path=DEFAULT_SINK_FIRMWARE_PATH, source_firmware_path=DEFAULT_SOURCE_FIRMWARE_PATH, exp_id=None, channel=DEFAULT_CHANNEL, reflash=False, tmux_target=None, mode=DEFAULT_MODE, data_len=DEFAULT_DATA_LEN, count=DEFAULT_COUNT, delay=DEFAULT_DELAY, run_duration=None, sniff=False, api=None): if name is None: name = DEFAULT_EXP_NAME_FORMAT.format(network=network, channel=channel) if api is None: api = get_default_api() logging.info("Building firmwares") env = {"MODE": mode, "DEFAULT_CHANNEL": str(channel)} sink_firmware = RIOTFirmware(sink_firmware_path, BOARD, SINK_FIRMWARE_NAME, env=env) threads = multiprocessing.cpu_count() sink_firmware.build(threads=threads) source_firmware = RIOTFirmware(source_firmware_path, BOARD, SOURCE_FIRMWARE_NAME, env=env) source_firmware.build(threads=threads) # select profiles if user wants to sniff if sniff: profiles = [_get_sniffer_profile(api, channel)] logging.info("Selected sniffing profile {}".format(profiles[0])) else: profiles = None # create and prepare IoT-LAB experiment try: exp = TmuxExperiment(name, network, run_experiment, [sink_firmware] + (len(network) - 1) * [source_firmware], exp_id, profiles, mode=mode, count=count, data_len=data_len, delay=delay, sniff=sniff, run_duration=run_duration, api=api) except ExperimentError as e: if os.path.exists(RUNNING_EXPERIMENT_FILE): os.remove(RUNNING_EXPERIMENT_FILE) raise e if exp.is_scheduled(): try: if sniff: logging.info(" ... (re-)setting sniffing profile") res = network.profile(exp.exp_id, profiles[0]) if '1' in res: logging.error(pprint.pformat(res)) sys.exit(1) else: logging.debug(pprint.pformat(res)) logging.info(" ... waiting for experiment {} to start".format( exp.exp_id)) exp.wait() if reflash: logging.info(" - reflashing firmwares") res = network.flash(exp.exp_id, source_firmware, sink_firmware) else: logging.info(" - resetting nodes") res = network.reset(exp.exp_id) if '1' in res: logging.error(pprint.pformat(res)) sys.exit(1) else: logging.debug(pprint.pformat(res)) except urllib.error.HTTPError as e: if os.path.exists(RUNNING_EXPERIMENT_FILE): os.remove(RUNNING_EXPERIMENT_FILE) raise e else: logging.info("Scheduling experiment with duration {}".format(duration)) exp.schedule(duration) logging.info(" - Experiment ID: {}".format(exp.exp_id)) with open(RUNNING_EXPERIMENT_FILE, "w") as running_exp: running_exp.write("-i {}".format(exp.exp_id)) logging.info(" ... waiting for experiment to start") exp.wait() tmux_target = _parse_tmux_target(tmux_target, name) logging.info("Starting TMUX session in {}".format(tmux_target)) tmux_session = exp.initialize_tmux_session(**tmux_target) assert tmux_session exp.hit_ctrl_c() # Kill potentially still running experiment time.sleep(.1) exp.run()