diff --git a/g5k/02_environment_control_resource_selection.ipynb b/g5k/02_environment_control_resource_selection.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..c8384aaad7e7a1996493f10f28f97be0b47057eb
--- /dev/null
+++ b/g5k/02_environment_control_resource_selection.ipynb
@@ -0,0 +1,399 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "86083fcd-c5b4-42c0-80f6-218784cb5647",
+   "metadata": {},
+   "source": [
+    "# Resources selection and environment control\n",
+    "\n",
+    "Get the resources that fit your need in terms of servers characteristics, network, disks and Operating Systems. Controlling what you get is a first step towards experiments reproducibility.\n",
+    "\n",
+    "\n",
+    "---\n",
+    "\n",
+    "- Website: https://discovery.gitlabpages.inria.fr/enoslib/index.html\n",
+    "- Instant chat: https://framateam.org/enoslib\n",
+    "- Source code: https://gitlab.inria.fr/discovery/enoslib\n",
+    "\n",
+    "---\n",
+    "\n",
+    "## Prerequisites\n",
+    "\n",
+    "<div class=\"alert alert-block alert-warning\">\n",
+    "    <ul>\n",
+    "    <li>⚠️ Make sure you've run the one time setup for your environment</li>\n",
+    "    <li>⚠️ Make sure you're running this notebook under the right kernel</li>\n",
+    "    </ul>\n",
+    "</div>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "0ff9540e-e238-4a4c-829a-7ada3ea4cf49",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import enoslib as en\n",
+    "\n",
+    "# Display some general information about the library\n",
+    "en.check()\n",
+    "\n",
+    "# Enable rich logging\n",
+    "_ = en.init_logging()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d8f785dd-460b-4d61-a425-af64f136cfb8",
+   "metadata": {},
+   "source": [
+    "## General considerations\n",
+    "\n",
+    "\n",
+    "Grid'5000 uses the [OAR](https://oar.imag.fr) scheduler behind the scene. The scheduler has powerful resource selections capabilities. You can refer to [some of the Grid'5000 tutorials](https://www.grid5000.fr/w/Getting_Started#Discovering,_visualizing_and_reserving_Grid'5000_resources) to explore them.\n",
+    "\n",
+    "EnOSlib exposes a higher level interface for selecting resources which is based on the [Grid'5000 REST API](https://api.grid5000.fr/) (which wraps OAR). \n",
+    "In EnOSlib you can reserve compute resources, networks (provided by Grid5000) and disks with the following assumptions:\n",
+    "\n",
+    "- Nodes are reserved as a whole (this makes a difference with OAR supports to reserve part of a node)\n",
+    "- Networks are those offered by Grid'5000 (Layer 3 subnets and Layer 2 VLANS - possibly spanning multiple sites)\n",
+    "- Local disks are reserved with there associated machines\n",
+    "\n",
+    "## Nodes selection\n",
+    "\n",
+    "\n",
+    "### By cluster name\n",
+    "\n",
+    "\n",
+    "In EnOSlib you can reserve some nodes by specifying the cluster name. The summary of all the available cluster is summarized in [the hardware page](https://www.grid5000.fr/w/Hardware#Clusters) of the Grid'5000 documentation.\n",
+    "EnOSlib supports the so called multisite experiments (experiments spanning different sites) easily. To illustrate this let's reserve nodes from different sites. The multisites experiment requires to synchronize jobs on different sites. EnOSlib eases this process for you.\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ef09e268-dd91-493f-b02c-896d65b8fc73",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "job_name=\"multisite\"\n",
+    "conf = (\n",
+    "    en.G5kConf.from_settings(job_type=[], job_name=job_name, walltime=\"0:10:00\")\n",
+    "    # For convenience, we use the site name as role\n",
+    "    .add_machine(roles=[\"rennes\", \"intel\"], cluster=\"paravance\", nodes=1)\n",
+    "    .add_machine(roles=[\"lille\", \"amd\"], cluster=\"chiclet\", nodes=1)\n",
+    ")\n",
+    "provider = en.G5k(conf)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f309e434-a245-4af0-94bc-c297907c5f10",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "roles, networks = provider.init()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b7df9949-8096-4e3b-a632-f873a2d74859",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "en.run_command(\"cat /proc/cpuinfo\", roles=roles)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bb205e6f-06d2-4d22-a16b-1a04d95c2c91",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "provider.destroy()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5a7d423f-261f-4387-8c9f-b4773452aaa0",
+   "metadata": {},
+   "source": [
+    "## By server names\n",
+    "\n",
+    "On Grid’5000, machines belonging to a given cluster are normally homogeneous. But it is impossible to provide absolute guarantees about it: for instance, physical disks may have different performance characteristics across nodes of a cluster even though they share the same vendor and model. For this reason, experimenters may need to reproduce an experiment several times using the exact same hardware.\n",
+    "\n",
+    "This is possible by specifying nodes with their exact name. By default all the servers specified this way will get reserved unless you specify a target number of nodes using the nodes parameter.\n",
+    "\n",
+    "\n",
+    "<div class=\"alert alert-warning\">\n",
+    "    In the following make sure to change the servers list, otherwise your reservation will conflict with others.\n",
+    "</div>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b4b559ee-c2f3-4ee5-b600-6a536c1ff44a",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "job_name = \"specific-server\"\n",
+    "conf = (\n",
+    "    en.G5kConf()\n",
+    "    .from_settings(job_name=job_name, walltime=\"0:10:00\")\n",
+    "    .add_machine(\n",
+    "        roles=[\"compute\"],\n",
+    "        servers=[\"paravance-19.rennes.grid5000.fr\", \"paravance-20.rennes.grid5000.fr\"],\n",
+    "    )\n",
+    ")\n",
+    "\n",
+    "\n",
+    "provider = en.G5k(conf)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a54af459-1cd7-4dd0-a7e6-b951e07eb763",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "roles, networks = provider.init()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c665fddd-b18f-4b2f-bda6-7a43683bd49d",
+   "metadata": {},
+   "source": [
+    "## Non default network selection"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e8dfc6c8-a144-4fc7-9398-b92d5b11e2d4",
+   "metadata": {},
+   "source": [
+    "In all of the above we get the default network resource (the \"production network\"). This network is shared with other users.\n",
+    "There are two other types of networks:\n",
+    "- `subnets`, which can be used if you need to assign extra addresses to your nodes (e.g virtual machines)\n",
+    "- `kavlans` are layer 2 isolated network. Using this network type currently requires an extra step after getting the resources: **a deployement** of a full OS on the node.\n",
+    "\n",
+    "<div class=\"alert alert-warning\">\n",
+    "    The number of kavlans is limited:\n",
+    "    <ul>\n",
+    "        <li>kavlan-local: 3 per sites (non routed network)</li>\n",
+    "        <li>kavlan: 3 per sites (routed network)</li>\n",
+    "        <li>kavlan-global: 1 per site (allow multi site, isolated experiments)</li>\n",
+    "    </ul>\n",
+    "</div>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "86b1cfc2-5390-4092-9226-7512d8c85490",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import logging\n",
+    "\n",
+    "job_name = \"vlan\"\n",
+    "\n",
+    "\n",
+    "\n",
+    "private_net = en.G5kNetworkConf(type=\"kavlan\", roles=[\"private\"], site=\"rennes\")\n",
+    "\n",
+    "conf = (\n",
+    "    en.G5kConf.from_settings(\n",
+    "        job_name=job_name,\n",
+    "        job_type=[\"deploy\"],\n",
+    "        env_name=\"debian11-nfs\",\n",
+    "        walltime=\"0:20:00\",\n",
+    "    )\n",
+    "    .add_network_conf(private_net)\n",
+    "    .add_machine(\n",
+    "        roles=[\"roleA\"], cluster=\"paravance\", nodes=1, primary_network=private_net\n",
+    "    )\n",
+    "    .finalize()\n",
+    ")\n",
+    "\n",
+    "provider = en.G5k(conf)\n",
+    "roles, networks = provider.init()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "fb1f62bc-a137-439e-9c77-4c25d136b405",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# checking the networks we got\n",
+    "networks"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "63556a22-4cbb-41c9-8d79-62e3a27db788",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Checking the ips of the nodes\n",
+    "roles = en.sync_info(roles, networks)\n",
+    "roles"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "464899d6-a7a9-4b65-99b7-504898cc14f8",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Show kavlan subnet\n",
+    "print(\"Kavlan subnet:\", networks[\"private\"][0].network)\n",
+    "\n",
+    "# The nodes use this kavlan network for all traffic\n",
+    "# (the network is interconnected at layer-3 with the rest of Grid'5000)\n",
+    "results = en.run_command(\"ip route get 9.9.9.9\", roles=roles[\"roleA\"])\n",
+    "\n",
+    "for result in results:\n",
+    "    print(f\"{result.stdout}\")\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9b44fe33-beef-4318-aafc-f40318840c0f",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# release resources\n",
+    "provider.destroy()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "6b036ad6-a3ee-418d-a5aa-7a7795bbe14c",
+   "metadata": {},
+   "source": [
+    "## Disk reservation primer\n",
+    "\n",
+    "Grid’5000 has a [disk reservation](https://www.grid5000.fr/w/Disk_reservation) feature: on several clusters, reserving secondary disks is mandatory if you want to use them in your experiments.\n",
+    "\n",
+    "Disk reservation feature addresses different use cases:\n",
+    "- benchmarking of storage\n",
+    "- long term storage of data local to the node computing them\n",
+    "\n",
+    "Let's have a look in the following\n",
+    "\n",
+    "<div class=\"alert alert-warning\">\n",
+    "    Make sure to specify a cluster that supports this feature -- refer to the documentation\n",
+    "</div>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "428a44f4-c9c8-4bfe-8dc1-f7126f49c36c",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "job_name = \"disks\"\n",
+    "conf = en.G5kConf.from_settings(\n",
+    "    job_name=job_name, job_type=[], walltime=\"0:30:00\"\n",
+    "\n",
+    ").add_machine(\n",
+    "    roles=[\"storage\"],\n",
+    "    cluster=\"gros\",\n",
+    "    nodes=1,\n",
+    ")\n",
+    "\n",
+    "with en.G5k(conf) as (roles, _):\n",
+    "    results = en.run_command(\"lsblk\", roles=roles)\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9f5f7790-1d96-49bf-8206-b5debb3b18fb",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# no extra disk available\n",
+    "print(results[0].stdout)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d5e22b94-c7d2-4410-a187-5c66568d41c4",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "a854cc54-23e2-474f-9f80-b456295efd2b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "job_name = \"disks\"\n",
+    "conf = en.G5kConf.from_settings(\n",
+    "    job_name=job_name, job_type=[], walltime=\"0:30:00\"\n",
+    "\n",
+    ").add_machine(\n",
+    "    roles=[\"storage\"],\n",
+    "    cluster=\"gros\",\n",
+    "    nodes=1,\n",
+    "    reservable_disks=True\n",
+    ")\n",
+    "\n",
+    "with en.G5k(conf) as (roles, _):\n",
+    "    results = en.run_command(\"lsblk\", roles=roles)\n",
+    "\n",
+    "results"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "4f376c24-b595-4118-9416-4d559f2e4e38",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# another disk is available\n",
+    "print(results[0].stdout)"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "my_venv",
+   "language": "python",
+   "name": "my_venv"
+  },
+  "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.9.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}