예제 #1
0
    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)
예제 #2
0
 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()
예제 #3
0
 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 = {}
예제 #4
0
 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()
예제 #5
0
 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
예제 #6
0
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
예제 #7
0
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)
예제 #8
0
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()