{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Grid'5000 and FIT/IoT-LAB - IPv6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This example shows how to interact with both platforms in a single experiment.\n", "\n", "An IPv6 network is built in IoT-LAB platform, composed of a border sensor and CoAP servers.\n", "A node in Grid'5000 is the client, which uses a CoAP client to read the sensor using its global IPv6 address.\n", "\n", "Inspired on: https://www.iot-lab.info/legacy/tutorials/contiki-coap-m3/index.html" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from enoslib import *\n", "import logging\n", "import sys" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Configuring logging: save DEBUG to a file and INFO to stdout" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "log = logging.getLogger()\n", "log.setLevel(logging.DEBUG)\n", "\n", "formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')\n", "fileHandler = logging.FileHandler(\"debug.log\", 'a')\n", "fileHandler.setLevel(logging.DEBUG)\n", "fileHandler.setFormatter(formatter)\n", "log.addHandler(fileHandler)\n", "\n", "cformat = logging.Formatter(\"[%(levelname)8s] : %(message)s\")\n", "consoleHandler = logging.StreamHandler(sys.stdout)\n", "consoleHandler.setFormatter(cformat)\n", "consoleHandler.setLevel(logging.INFO)\n", "log.addHandler(consoleHandler)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Getting resources" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### IoT-LAB provider configuration: reserve M3 nodes in saclay site\n", "\n", "Note: It uses the following M3 images: border-router.iotlab-m3 and er-example-server.iotlab-m3.\n", "\n", "More details on how to generate these images in: https://www.iot-lab.info/legacy/tutorials/contiki-coap-m3/index.html" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "job_name=\"iotlab_g5k-ipv6\"\n", "iotlab_dict = {\n", " \"walltime\": \"01:00\",\n", " \"job_name\": job_name,\n", " \"resources\": {\n", " \"machines\": [\n", " {\n", " \"roles\": [\"border_router\"],\n", " \"archi\": \"m3:at86rf231\",\n", " \"site\": \"saclay\",\n", " \"number\": 1,\n", " \"image\": \"border-router.iotlab-m3\",\n", " },\n", " {\n", " \"roles\": [\"sensor\"],\n", " \"archi\": \"m3:at86rf231\",\n", " \"site\": \"saclay\",\n", " \"number\": 2,\n", " \"image\": \"er-example-server.iotlab-m3\",\n", " },\n", " ]\n", " },\n", "}\n", "iotlab_conf = IotlabConf.from_dictionary(iotlab_dict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Grid'5000 provider configuration: reserve nodes in grenoble" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g5k_dict = {\n", " \"job_type\": [],\n", " \"job_name\": job_name,\n", " \"resources\": {\n", " \"machines\": [\n", " {\n", " \"roles\": [\"client\"],\n", " \"cluster\": \"yeti\",\n", " \"nodes\": 1,\n", " \"primary_network\": \"default\",\n", " \"secondary_networks\": [],\n", " },\n", " ],\n", " \"networks\": [\n", " {\"id\": \"default\", \"type\": \"prod\", \"roles\": [\"my_network\"], \"site\": \"grenoble\"}\n", " ],\n", " },\n", "}\n", "g5k_conf = G5kConf.from_dictionnary(g5k_dict)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### We still need a Static provider to interact with the IoT-LAB frontend machine" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import iotlabcli.auth\n", "iotlab_user, _ = iotlabcli.auth.get_user_credentials()\n", "\n", "iotlab_frontend_conf = (\n", " StaticConf()\n", " .add_machine(\n", " roles=[\"frontend\"],\n", " address=\"saclay.iot-lab.info\",\n", " alias=\"saclay\",\n", " user=iotlab_user\n", " )\n", " .finalize()\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### IoT-LAB: getting resources" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "iotlab_provider = Iotlab(iotlab_conf)\n", "iotlab_roles, _ = iotlab_provider.init()\n", "print(iotlab_roles)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Grid'5000: getting resources" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g5k_provider = G5k(g5k_conf)\n", "g5k_roles, g5knetworks = g5k_provider.init()\n", "print(g5k_roles)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Static: getting resources" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "frontend_provider = Static(iotlab_frontend_conf)\n", "frontend_roles, _ = frontend_provider.init()\n", "print(frontend_roles)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Configuring network connectivity" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Enabling IPv6 on Grid'5000 nodes (https://www.grid5000.fr/w/IPv6)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result=run_command(\"dhclient -6 br0\", roles=g5k_roles)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result = run_command(\"ip address show dev br0\", roles=g5k_roles)\n", "print(result['ok'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Starting tunslip command in frontend.\n", "\n", "Redirect tunslip command output to a file to read it later." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "iotlab_ipv6_net=\"2001:660:3207:4c0::\"\n", "tun_cmd = \"sudo tunslip6.py -v2 -L -a %s -p 20000 %s1/64 > tunslip.output 2>&1\" % (iotlab_roles[\"border_router\"][0].alias, iotlab_ipv6_net)\n", "result=run_command(tun_cmd, roles=frontend_roles, asynch=3600, poll=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Reseting border router" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "iotlab_roles[\"border_router\"][0].reset()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Get the Border Router IPv6 address from tunslip output" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result = run_command(\"cat tunslip.output\", roles=frontend_roles)\n", "print(result['ok'])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import re\n", "out = result['ok']['saclay']['stdout']\n", "print(out)\n", "match = re.search(rf'Server IPv6 addresses:\\n.+({iotlab_ipv6_net}\\w{{4}})', out, re.MULTILINE|re.DOTALL)\n", "br_ipv6 = match.groups()[0]\n", "print(\"Border Router IPv6 address from tunslip output: %s\" % br_ipv6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Checking ping from Grid'5000 to border router node" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result = run_command(\"ping6 -c3 %s\" % br_ipv6, pattern_hosts=\"client*\", roles=g5k_roles)\n", "print(result['ok'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Installing and using CoAP clients" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Install aiocoap client and lynx on grid'5000 nodes" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "with play_on(roles=g5k_roles) as p:\n", " p.apt(name=[\"python3-aiocoap\", \"lynx\"], state=\"present\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Grab the CoAP server node’s IPv6 address from the BR’s web interface" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result = run_command(\"lynx -dump http://[%s]\" % br_ipv6, roles=g5k_roles)\n", "print(result['ok'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### For a CoAP server, GET light sensor" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "out = result['ok'][g5k_roles[\"client\"][0].address]['stdout']\n", "print(out)\n", "match = re.search(r'fe80::(\\w{4})', out, re.MULTILINE|re.DOTALL)\n", "node_uid = match.groups()[0]\n", "print(node_uid)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result = run_command(\"aiocoap-client coap://[%s%s]:5683/sensors/light\" % (iotlab_ipv6_net, node_uid), roles=g5k_roles)\n", "print(result['ok'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### GET pressure for the same sensor" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result = run_command(\"aiocoap-client coap://[%s%s]:5683/sensors/pressure\" % (iotlab_ipv6_net, node_uid), roles=g5k_roles)\n", "print(result['ok'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Clean-up phase" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Stop tunslip in frontend node" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "result = run_command(\"pgrep tunslip6 | xargs kill\", roles=frontend_roles)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Destroy jobs in testbeds" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "g5k_provider.destroy()\n", "iotlab_provider.destroy()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }