<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Grid'5000 and FIT/IoT-LAB - IPv6
Introduction
This example shows how to interact with both platforms in a single experiment.
An IPv6 network is built in IoT-LAB platform, composed of a border sensor and CoAP servers.
A node in Grid'5000 is the client, which uses a CoAP client to read the sensor using its global IPv6 address.
Inspired on
Step1:  Configuring logging
Step2:  Getting resources
IoT-LAB provider configuration
Step3:  Grid'5000 provider configuration
Step4:  We still need a Static provider to interact with the IoT-LAB frontend machine
Step5:  IoT-LAB
Step6:  Grid'5000
Step7:  Static
Step8:  Configuring network connectivity
Enabling IPv6 on Grid'5000 nodes (https
Step9:  Starting tunslip command in frontend.
Redirect tunslip command output to a file to read it later.
Step10:  Reseting border router
Step11:  Get the Border Router IPv6 address from tunslip output
Step12:  Checking ping from Grid'5000 to border router node
Step13:  Installing and using CoAP clients
Install aiocoap client and lynx on grid'5000 nodes
Step14:  Grab the CoAP server node’s IPv6 address from the BR’s web interface
Step15:  For a CoAP server, GET light sensor
Step16:  GET pressure for the same sensor
Step17:  Clean-up phase
Stop tunslip in frontend node
Step18:  Destroy jobs in testbeds
<ASSISTANT_TASK:>
Python Code:
from enoslib import *
import logging
import sys
Explanation: Grid'5000 and FIT/IoT-LAB - IPv6
Introduction
This example shows how to interact with both platforms in a single experiment.
An IPv6 network is built in IoT-LAB platform, composed of a border sensor and CoAP servers.
A node in Grid'5000 is the client, which uses a CoAP client to read the sensor using its global IPv6 address.
Inspired on: https://www.iot-lab.info/legacy/tutorials/contiki-coap-m3/index.html
End of explanation
log = logging.getLogger()
log.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fileHandler = logging.FileHandler("debug.log", 'a')
fileHandler.setLevel(logging.DEBUG)
fileHandler.setFormatter(formatter)
log.addHandler(fileHandler)
cformat = logging.Formatter("[%(levelname)8s] : %(message)s")
consoleHandler = logging.StreamHandler(sys.stdout)
consoleHandler.setFormatter(cformat)
consoleHandler.setLevel(logging.INFO)
log.addHandler(consoleHandler)
Explanation: Configuring logging: save DEBUG to a file and INFO to stdout
End of explanation
job_name="iotlab_g5k-ipv6"
iotlab_dict = {
    "walltime": "01:00",
    "job_name": job_name,
    "resources": {
        "machines": [
            {
                "roles": ["border_router"],
                "archi": "m3:at86rf231",
                "site": "saclay",
                "number": 1,
                "image": "border-router.iotlab-m3",
            },
            {
                "roles": ["sensor"],
                "archi": "m3:at86rf231",
                "site": "saclay",
                "number": 2,
                "image": "er-example-server.iotlab-m3",
            },
        ]
    },
}
iotlab_conf = IotlabConf.from_dictionary(iotlab_dict)
Explanation: Getting resources
IoT-LAB provider configuration: reserve M3 nodes in saclay site
Note: It uses the following M3 images: border-router.iotlab-m3 and er-example-server.iotlab-m3.
More details on how to generate these images in: https://www.iot-lab.info/legacy/tutorials/contiki-coap-m3/index.html
End of explanation
g5k_dict = {
    "job_type": "allow_classic_ssh",
    "job_name": job_name,
    "resources": {
        "machines": [
            {
                "roles": ["client"],
                "cluster": "yeti",
                "nodes": 1,
                "primary_network": "default",
                "secondary_networks": [],
            },
        ],
        "networks": [
            {"id": "default", "type": "prod", "roles": ["my_network"], "site": "grenoble"}
        ],
    },
}
g5k_conf = G5kConf.from_dictionnary(g5k_dict)
Explanation: Grid'5000 provider configuration: reserve nodes in grenoble
End of explanation
import iotlabcli.auth
iotlab_user, _ = iotlabcli.auth.get_user_credentials()
iotlab_frontend_conf = (
    StaticConf()
    .add_machine(
        roles=["frontend"],
        address="saclay.iot-lab.info",
        alias="saclay",
        user=iotlab_user
    )
    .finalize()
)
Explanation: We still need a Static provider to interact with the IoT-LAB frontend machine
End of explanation
iotlab_provider = Iotlab(iotlab_conf)
iotlab_roles, _ = iotlab_provider.init()
print(iotlab_roles)
Explanation: IoT-LAB: getting resources
End of explanation
g5k_provider = G5k(g5k_conf)
g5k_roles, g5knetworks = g5k_provider.init()
print(g5k_roles)
Explanation: Grid'5000: getting resources
End of explanation
frontend_provider = Static(iotlab_frontend_conf)
frontend_roles, _ = frontend_provider.init()
print(frontend_roles)
Explanation: Static: getting resources
End of explanation
result=run_command("dhclient -6 br0", roles=g5k_roles)
result = run_command("ip address show dev br0", roles=g5k_roles)
print(result['ok'])
Explanation: Configuring network connectivity
Enabling IPv6 on Grid'5000 nodes (https://www.grid5000.fr/w/IPv6)
End of explanation
iotlab_ipv6_net="2001:660:3207:4c0::"
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)
result=run_command(tun_cmd, roles=frontend_roles, asynch=3600, poll=0)
Explanation: Starting tunslip command in frontend.
Redirect tunslip command output to a file to read it later.
End of explanation
iotlab_roles["border_router"][0].reset()
Explanation: Reseting border router
End of explanation
result = run_command("cat tunslip.output", roles=frontend_roles)
print(result['ok'])
import re
out = result['ok']['saclay']['stdout']
print(out)
match = re.search(rf'Server IPv6 addresses:\n.+({iotlab_ipv6_net}\w{{4}})', out, re.MULTILINE|re.DOTALL)
br_ipv6 = match.groups()[0]
print("Border Router IPv6 address from tunslip output: %s" % br_ipv6)
Explanation: Get the Border Router IPv6 address from tunslip output
End of explanation
result = run_command("ping6 -c3 %s" % br_ipv6, pattern_hosts="client*", roles=g5k_roles)
print(result['ok'])
Explanation: Checking ping from Grid'5000 to border router node
End of explanation
with play_on(roles=g5k_roles) as p:
    p.apt(name=["python3-aiocoap", "lynx"], state="present")
Explanation: Installing and using CoAP clients
Install aiocoap client and lynx on grid'5000 nodes
End of explanation
result = run_command("lynx -dump http://[%s]" % br_ipv6, roles=g5k_roles)
print(result['ok'])
Explanation: Grab the CoAP server node’s IPv6 address from the BR’s web interface
End of explanation
out = result['ok'][g5k_roles["client"][0].address]['stdout']
print(out)
match = re.search(r'fe80::(\w{4})', out, re.MULTILINE|re.DOTALL)
node_uid = match.groups()[0]
print(node_uid)
result = run_command("aiocoap-client coap://[%s%s]:5683/sensors/light" % (iotlab_ipv6_net, node_uid), roles=g5k_roles)
print(result['ok'])
Explanation: For a CoAP server, GET light sensor
End of explanation
result = run_command("aiocoap-client coap://[%s%s]:5683/sensors/pressure" % (iotlab_ipv6_net, node_uid), roles=g5k_roles)
print(result['ok'])
Explanation: GET pressure for the same sensor
End of explanation
result = run_command("pgrep tunslip6 | xargs kill", roles=frontend_roles)
Explanation: Clean-up phase
Stop tunslip in frontend node
End of explanation
g5k_provider.destroy()
iotlab_provider.destroy()
Explanation: Destroy jobs in testbeds
End of explanation
<END_TASK>