{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Network File System (NFS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Outline of the NFS topic\n",
    "\n",
    "- Network File System  (NFS) sharing.\n",
    "- Services involved in NFS\n",
    "- File system exporting and mounting\n",
    "- NFS server setup on a VM\n",
    "- NFS client setup on a VM\n",
    "- File access permissions on a server\n",
    "- Automount\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## File system sharing over network\n",
    "\n",
    "NFS defines a method of sharing files in which files residing on one or more remote servers can be accessed on a local client system in a manner that makes them appear as local files and directories.\n",
    "\n",
    "\n",
    "![](img/nfs_pic.gif)\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS versions\n",
    "\n",
    "- NFS was originally developed by Sun Microsystems:\n",
    "\n",
    "```{admonition} NFS versions\n",
    "    NFSv2 released in 1985 (no longer supported on Ubuntu and RedHat)\n",
    "    NFSv3 released in 1995\n",
    "    NFSv4 released in 2003 (developed by Internet Engineering Task Force (IETF)) \n",
    "    NFSv4.1 released in 2010\n",
    "    NFSv4.2 released in 2016\n",
    "```\n",
    "\n",
    "- Detailed info about the NFS versions for Linux is available at on Wiki (Links to an external site.)\n",
    "NFS support should be enabled in Linux kernel. Check the kernel config file for 'CONFIG_NFS':\n",
    "\n",
    "```bash\n",
    "grep CONFIG_NFS /boot/config-*\n",
    "```\n",
    "\n",
    "````{admonition} output\n",
    "    CONFIG_NFS_V2=m\n",
    "    CONFIG_NFS_V3=m\n",
    "    CONFIG_NFS_V3_ACL=y\n",
    "    CONFIG_NFS_V4=m\n",
    "    CONFIG_NFS_V4_1=y\n",
    "    CONFIG_NFS_V4_2=y\n",
    "    CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN=\"kernel.org\"\n",
    "    CONFIG_NFS_V4_1_MIGRATION=y\n",
    "    CONFIG_NFS_V4_SECURITY_LABEL=y\n",
    "\n",
    "````\n",
    "\n",
    "\n",
    "<hr>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## File system virtualization\n",
    "\n",
    "- VFS is an abstraction of a local file system provided by Kernel for an application.\n",
    "- Platform independent.\n",
    "- Preserves or emulates Unix file system semantics.\n",
    "\n",
    "![](img/VFS.jpg)\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example of physical file locations\n",
    "\n",
    "\n",
    "In a python script we may use files referenced by their full path:\n",
    "```c\n",
    "f1 = open(\"/home/hostadm/python/parameters.txt\",\"w\")\n",
    "f2 = open(\"/NFS/python/parameters.txt\",\"w\")\n",
    "```\n",
    "\n",
    "Files ```f1``` and ```f2``` can physically reside anywhere, on the local file system or NFS.\n",
    "The application doesn't care. It is the task of the VFS to provide access to the files by their full path. \n",
    "\n",
    "***"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS and RPC\n",
    "\n",
    "- NFS utilizes Remote Procedure Calls (RPC) layer for server -- client communications.\n",
    "\n",
    "- Marshalling - Packaging arguments in XDR (eXternal Data Representation) format.\n",
    "\n",
    "- XDR format is platform independent\n",
    "\n",
    "- RPC allows applications on one host to call procedures (functions) on the other remote host\n",
    "\n",
    "- RPC allows a server to respond to more than one version of a protocol at the same time (NFS 4 or 3).\n",
    "\n",
    "![](img/NFS-RPC.jpg)\n",
    "\n",
    "<hr>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS in the 7 layer OSI tcp/ip protocol\n",
    "\n",
    "- NFS, XDR and RPC fit into the top 3 layes of the OSI model.\n",
    "- XDR translates DATA into canonical (platform independent) format\n",
    "- RPC provides remote procedure calls that appear as local processes.\n",
    "\n",
    "![](img/NFS_OSI.jpg)\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS server daemons\n",
    "\n",
    "- Daemons are processes running on a server and providing some services.\n",
    "- Several daemons are involved in NFS.\n",
    "- The same server can offer  NFSv4 and NFSv3 file system access. It is up to the client to decide which version to use.\n",
    "\n",
    "\n",
    "|NFS version 3 server daemons:  |   \tNFS version 4 server daemons: |\n",
    "| :-- | --: |\n",
    "|<b>rpcbind</b> <I>handles RPC requests and registers ports for RPC services.</I> | <I>(Unnecessary in NFSv4. Good to have for diagnostics.)</I>\n",
    "|<b>rpc.mountd</b> <I>handles the initial mount requests.</I>  | <b>rpc.mountd</b> <I>handles the initial mount requests.</I> |\n",
    "|<b>nfsd or [nfsd]</b> <I>handles data streaming.</I>  |  <b>nfsd or [nfsd]</b> <I>handles data streaming.</I> |\n",
    "|<b>rpc.rquotad</b> <I>handles user file quotas on exported volumes.</I> |  |\n",
    "|<b>rpc.lockd</b> <I>handles file locking to make sure several processes don't write into the same file.</I>  |  |\n",
    "|<b>rpc.statd</b> <I>Interacts with the rpc.lockd daemon and provides crash and recovery for the locking services.</I> | |\n",
    "| | <b>rpc.idmapd</b> <I> handles user and group mapping (optional).</I> |\n",
    "\n",
    "\n",
    "- To verify that the services have started and registeresd with rpcbind, run command\n",
    "\n",
    "    ```bash\n",
    "    rpcinfo -p\n",
    "    ```\n",
    "    \n",
    "- To see rpc services on a remote host, for example with IP address 192.168.112.3:\n",
    "\n",
    "    ```bash\n",
    "    rpcinfo -p 192.168.112.3\n",
    "    ```\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS client daemons\n",
    "\n",
    "| NFS version 3  client daemons\t|  NFS version 4 client daemons |\n",
    "| :-- | --: |\n",
    "|rpcbind | rpcbind (unnecessary) |\n",
    "|rpc.lockd |    |\n",
    "|rpc.statd\t|   |\n",
    "|  |rpc.idmapd (optional) |\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS mount and file handle\n",
    "\n",
    "- An NFS client receives <I>file handles</I> from NFS server when executes mount and lookup calls.\n",
    "\n",
    "![mount](img/mount_lookup.jpg)\n",
    "\n",
    "- The <I>file handles</I> on a client relate to the file pointers on an NFS server (inode number, disk device number, and inode generation number).\n",
    "- If the NFS server crashes or reboots, NFS dependent applications on the client hang and then continue running after the server becomes available.\n",
    "- If the <I>file system</I> on the server is changed or corrupted, the client gets a stale <I>file handle</I> error.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Export/mount directory over NFS\n",
    "- NFS server exports a directory and NFS client mounts it.\n",
    "- NFS server may run several versions of NFS, for example, NFSv3, and NFSv4.\n",
    "- NFS client chooses the NFS version at the mount time.\n",
    "\n",
    "\n",
    "\n",
    "<hr>\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Remove old unneded VM (exercise)\n",
    "\n",
    "To reclaim some disk space, let's remove ```netplan``` VM:\n",
    "```bash\n",
    "virsh shutdown netplan\n",
    "virsh undefine netplan\n",
    "cd KVM\n",
    "rm netplan.qcow2\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## VM setup for NFS (Exercises)\n",
    "\n",
    "Clone kvm1 to a new NFS server VM host, master, by executing the command below:\n",
    "\n",
    "```bash\n",
    "virt-clone  -o kvm1 -n master -f /home/hostadm/KVM/master.qcow2\n",
    "```\n",
    "    \n",
    "Check if the new VM is in the list, start it, then login to its console:\n",
    "\n",
    "```bash\n",
    "virsh list --all\n",
    "virsh start master\n",
    "virsh console master\n",
    "```\n",
    "    \n",
    "Fix the host name:\n",
    "Replace kvm1 with master in /etc/hostname file.\n",
    "Reset the machine ID by running the following commands on master:\n",
    "\n",
    "```bash\n",
    "./vm_id_reset.sh\n",
    "```\n",
    "    \n",
    "    \n",
    "Execute command reboot\n",
    "Reboot the VM. After reboot, the new VM should come up with the correct host name and the MAC address.\n",
    "Clone kvm1 to a new NFS client VM host, n01, by executing the command below:\n",
    "\n",
    "```bash\n",
    "virt-clone -o kvm1 -n n01 -f /home/hostadm/KVM/n01.qcow2\n",
    "```\n",
    "    \n",
    "Fix the host name and the host ID of n01 in the same way as for master VM above.\n",
    "Both the VMs need to be able to communicate with each other by their host names, therefore we need to define their host name-to-ip match in /etc/hosts files. In /etc/hosts file on the master put the IP addreaas of n01 and host name n01, for example:\n",
    "\n",
    "```\n",
    "192.168.122.216    n01\n",
    "```\n",
    "\n",
    "On n01 VM, similarly set the host name resolution for the master in /etc/hosts file, for example:\n",
    "\n",
    "```\n",
    "192.168.122.9    master\n",
    "```\n",
    "\n",
    "Note, the IP addresses may be different from above for your VMs\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Update Linux kernel on master VM (Exercises)\n",
    "\n",
    "On the master, run command below\n",
    "\n",
    "```bash\n",
    "cd /boot\n",
    "grep NFS config-5.15.0-1059-kvm\n",
    "```\n",
    "It shows\n",
    "```{admonition} in the output, there is:\n",
    "    # CONFIG_NFSD is not set\n",
    "```\n",
    "The kernel is not suitable for running NFS server.\n",
    "\n",
    "Install the latest linux kernel by running following commands on master VM:\n",
    "```bash\n",
    "sudo apt install linux-image-6.5.0-45-generic\n",
    "```\n",
    "Reboot the VM. \n",
    "\n",
    "Login to the VM, then remove the old kernel package:\n",
    "```bash\n",
    "sudo apt remove linux-image-5.15.0-1059-kvm\n",
    "```\n",
    "\n",
    "Run command below to verify that you are running the installed kernel:\n",
    "```bash\n",
    "uname -a\n",
    "```\n",
    "\n",
    "Run \n",
    "```bash\n",
    "grep NFS /boot/config-6.5.0-45-generic\n",
    "```\n",
    "it shows ```CONFIG_NFSD=m``` and ```CONFIG_NFSD_V4=y```, which means we can install and run NFS server.\n",
    "***\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS server configuration (Exercises)\n",
    "Install NFS server packages on master VM by following the instructions below.\n",
    "\n",
    "```bash\n",
    "apt install rpcbind nfs-common nfs-kernel-server\n",
    "```\n",
    "\n",
    "Create a directory to export:\n",
    "\n",
    "```bash\n",
    "mkdir -p /NFS/home\n",
    "```\n",
    "\n",
    "Modify file `/etc/exports` to include the following entry:\n",
    "\n",
    "```{admonition} file content\n",
    "/NFS/home  n01(rw)\n",
    "```\n",
    "\n",
    "Make sure host n01 is reachable from master:\n",
    "\n",
    "```bash\n",
    "ping -c 2  n01\n",
    "```\n",
    "\n",
    "Restart the NFSv4 related service:\n",
    "\n",
    "```bash\n",
    "systemctl restart nfs-kernel-server\n",
    "```\n",
    "\n",
    "Make sure the services are running by executing command rpcinfo:\n",
    "\n",
    "```bash\n",
    "rpcinfo -p\n",
    "```\n",
    "\n",
    "You should see the following:\n",
    "\n",
    "```{admonition} output\n",
    "    program vers proto   port  service\n",
    "    100000    4   tcp    111  portmapper\n",
    "    100000    3   tcp    111  portmapper\n",
    "    100000    2   tcp    111  portmapper\n",
    "    100000    4   udp    111  portmapper\n",
    "    100000    3   udp    111  portmapper\n",
    "    100000    2   udp    111  portmapper\n",
    "    100024    1   udp  41147  status\n",
    "    100024    1   tcp  50021  status\n",
    "    100005    1   udp  45022  mountd\n",
    "    100005    1   tcp  47677  mountd\n",
    "    100005    2   udp  43482  mountd\n",
    "    100005    2   tcp  60947  mountd\n",
    "    100005    3   udp  50653  mountd\n",
    "    100005    3   tcp  36245  mountd\n",
    "    100003    3   tcp   2049  nfs\n",
    "    100003    4   tcp   2049  nfs\n",
    "    100227    3   tcp   2049\n",
    "    100003    3   udp   2049  nfs\n",
    "    100227    3   udp   2049\n",
    "    100021    1   udp  40359  nlockmgr\n",
    "    100021    3   udp  40359  nlockmgr\n",
    "    100021    4   udp  40359  nlockmgr\n",
    "    100021    1   tcp  37625  nlockmgr\n",
    "    100021    3   tcp  37625  nlockmgr\n",
    "    100021    4   tcp  37625  nlockmgr\n",
    "```\n",
    "\n",
    "Run command below to see what and how is exported by the NFS server:\n",
    "```bash\n",
    "showmount -e\n",
    "```\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS client configuration (Exercises)\n",
    "\n",
    "Install the NFS related packages by using apt on n01 VM:\n",
    "```bash\n",
    "apt install nfs-common\n",
    "```\n",
    "Run command rpcinfo pointing at the server:\n",
    "```bash\n",
    "rpcinfo -p master\n",
    "```\n",
    "If you see the same output as on the NFS server, it means the server allows you to access the rpcbind and the rpc services. Check what directories are exported to you from the server:\n",
    "```bash\n",
    "/sbin/showmount -e master\n",
    "```\n",
    "It should show:\n",
    "\n",
    "```{admonition} output\n",
    "    /NFS/home   n01\n",
    "```\n",
    "\n",
    "Now you are ready to mount its directory on n01. \n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS file system mount\n",
    "\n",
    "![NFS mount](img/NFS-mount.png)\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## NFS mount on a client  (Exercises)\n",
    "\n",
    "\n",
    "\n",
    "Create a new mounting point and mount the exported directory onto it via NFS:\n",
    "```bash\n",
    "mkdir -p /NFS/home\n",
    "mount  master:/NFS/home /NFS/home\n",
    "```\n",
    "To make sure the directory has been mounted, run command\n",
    "```bash\n",
    "mount\n",
    "```\n",
    "Run also\n",
    "```bash\n",
    "df -h\n",
    "```\n",
    "The mounted directory shows up in the bottom of the file systems list:\n",
    "\n",
    "```{admonition} output\n",
    "    master:/NFS/home   3.9G   1.5G   2.3G   39%  /NFS/home\n",
    "```\n",
    "\n",
    "\n",
    "Unmount the directory,\n",
    "```bash\n",
    "umount /NFS/home\n",
    "```\n",
    "\n",
    "Modify file /etc/fstab \n",
    "```bash\n",
    "nano /etc/fstab\n",
    "```\n",
    "include a new entry with /NFS/home:\n",
    "```{admonition} /etc/fstab\n",
    "    master:/NFS/home    /NFS/home    nfs    rw     0    0\n",
    "```\n",
    "\n",
    "Then run\n",
    "```bash\n",
    "mount -a\n",
    "```\n",
    "Check if it is mounted\n",
    "```bash\n",
    "df -h\n",
    "```\n",
    "\n",
    "Reboot n01 VM, login to the VM, and make sure /NFS/home gets mounted:\n",
    "\n",
    "```bash\n",
    "df -h\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## File access on NFS by uid match (Exercise)\n",
    "\n",
    "- To secure file access, NFS either assumes UID  match or has IDMAPD service configured.\n",
    "\n",
    "- We'll create two user accounts with mismatched UID first, then fix one to be the same as the other.\n",
    "\n",
    "- On the NFS server, master VM, create a new user with home directory in `/NFS/home`:\n",
    "\n",
    "```bash\n",
    "/usr/sbin/groupadd -g 1666 edward\n",
    "/usr/sbin/useradd -m -s /bin/bash -u 1666 -g 1666 -d /NFS/home/edward edward\n",
    "```\n",
    "\n",
    "Copy some files from `/etc` into directory `/NFS/home/edward` and give them ownership \"edward\":\n",
    "\n",
    "```bash\n",
    "cp /etc/hosts /NFS/home/edward\n",
    "cp /etc/nsswitch.conf /NFS/home/edward\n",
    "chown edward:edward /NFS/home/edward/*\n",
    "```\n",
    "\n",
    "Then\n",
    "\n",
    "```bash\n",
    "cp /etc/group /NFS/home/edward\n",
    "```\n",
    "\n",
    "and live it with root ownreship.\n",
    "\n",
    "\n",
    "- On the NFS client VM, n01,  run command\n",
    "```bash\n",
    "ls -l /NFS/home/edward\n",
    "```\n",
    "\n",
    "Since there is no user with UID=1666 and GID=1666 on the node, the mounted directory would belong to a non-existent user:\n",
    "```bash\n",
    "ls -l /NFS/home/edward\n",
    "```\n",
    "\n",
    "total 5\n",
    "```{admonition} output\n",
    "    -rw-r--r--    1 1666      1666           104 Feb 10 19:32 hosts\n",
    "    -rw-r--r--    1 1666      1666          1750 Feb 10 19:32 nsswitch.conf\n",
    "    -rw-------    1 root     root          114 Feb 10  2003 group\n",
    "```\n",
    "\n",
    "Create user edward with UID=GID=1667:\n",
    "```bash\n",
    "/usr/sbin/groupadd -g 1667 edward\n",
    "/usr/sbin/useradd -s /bin/bash -u 1667 -g 1667 -d /NFS/home/edward edward\n",
    "```\n",
    "\n",
    "Assign password to the user:\n",
    "```bash\n",
    "passwd edward\n",
    "```\n",
    "\n",
    "Now try to change the ownership of the directory on the node:\n",
    "```bash\n",
    "chown edward:edward /NFS/home/edward\n",
    "```\n",
    "\n",
    "It doesn't work:\n",
    "\n",
    "```{admonition} output\n",
    "    chown: changing ownership of `/NFS/home/edward': Operation not permitted\n",
    "```\n",
    "\n",
    "Change the UID and GID of edward to be consistent with those on the NFS server:\n",
    "```bash\n",
    "/usr/sbin/groupmod -g 1666 edward\n",
    "/usr/sbin/usermod -u 1666 -g 1666 edward\n",
    "```\n",
    "\n",
    "Become user edward then step into directory /NFS/home:\n",
    "```bash\n",
    "su edward\n",
    "cd /NFS/home/edward\n",
    "```\n",
    "\n",
    "and see if you can create files in this directory:\n",
    "```bash\n",
    "touch  newfile.txt\n",
    "```\n",
    "\n",
    "Exit from user edward account:\n",
    "```bash\n",
    "exit\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Unmounting busy directories (Exercises)\n",
    "\n",
    "Open another terminal on your desktop and ssh to n01 as user edward. You can figure out the IP address of n01 by running command ```ip addr ``` in the console of n01. \n",
    "For example, if n01 has IP address 192.168.122.64, the ssh command on the desktop looks as follows:\n",
    "```bash\n",
    "ssh edward@192.168.122.216\n",
    "```\n",
    "Note, in your KVM environment the IP address of n01 may be different.\n",
    "\n",
    "In the 'root' console of n01 try to unmount the directory:\n",
    "```bash\n",
    "umount /NFS/home\n",
    "```\n",
    "If the directory can not get unmounted and you receive error message \"device is busy\", check what processes hold the directory by executing command lsof +D on the file system. Specifically, in our case:\n",
    "```bash\n",
    "lsof +D  /NFS/home\n",
    "```\n",
    "Kill the process, for example with PID 1367, and try to unmount the directory again.\n",
    "```bash\n",
    "kill -9 1367\n",
    "umount /NFS/home\n",
    "```\n",
    "Comment the NFS entry in /etc/fstab file:\n",
    "```{admonition} /etc/fstab\n",
    "    # master:/NFS/home    /NFS/home    nfs   rw    0   0\n",
    "```\n",
    "\n",
    "Try to avoid NFS mounting through /etc/fstab. Use either manual mount or automount.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Automount (Exercises)\n",
    "\n",
    "Install autofs on n01 (NFS client).\n",
    "```bash\n",
    "apt install autofs\n",
    "```\n",
    "\n",
    "Make sure /NFS/home directory is unmounted:\n",
    "```bash\n",
    "df -h\n",
    "```\n",
    "If it shows in the list of mounted file systems, unmount it:\n",
    "```bash\n",
    "umount /NFS/home\n",
    "```\n",
    "\n",
    "Remove directory /NFS/home:\n",
    "```bash\n",
    "rmdir /NFS/home\n",
    "```\n",
    "Configure the master map file, /etc/auto.master, and specify the timeout 60 seconds. The content of file /etc/auto.master should be the following:\n",
    "\n",
    "```{admonition} /etc/auto.master:\n",
    "    /NFS   /etc/auto.exports  --timeout=30\n",
    "```\n",
    "\n",
    "Configure the exports map file, /etc/auto.exports:\n",
    "\n",
    "```{admonition} /etc/auto.exports:\n",
    "    home  -rw  master:/NFS/home\n",
    "```\n",
    "\n",
    "Restart or reload autofs:\n",
    "```bash\n",
    "systemctl restart autofs\n",
    "```\n",
    "\n",
    "Access the file system and check if it gets mounted:\n",
    "```bash\n",
    "cd /NFS/home\n",
    "df -h\n",
    "```\n",
    "\n",
    "Step out of the directory:\n",
    "```bash\n",
    "cd\n",
    "```\n",
    "Run command ```df -h``` again in about two minutes to see if it gets unmounted automatically after the inactivity period.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Stale NFS file handle (Exercise)\n",
    "On the NFS server, master, create a new directory tree under NFS exported directory:\n",
    "\n",
    "```bash\n",
    "mkdir -p /NFS/home/test/demo\n",
    "```\n",
    "On the client, n01, step into the directory:\n",
    "```bash\n",
    "cd /NFS/home/test\n",
    "ls\n",
    "```\n",
    "On the NFS server, master, remove directory test with its subdirectory:\n",
    "```bash\n",
    "cd /NFS/home\n",
    "rm -rf test\n",
    "```\n",
    "On the client, run\n",
    "```bash\n",
    "ls\n",
    "```\n",
    "It should give you the following error:\n",
    "```{admonition} output\n",
    "ls: cannot open directory .: Stale NFS file handle\n",
    "```\n",
    "\n",
    "Step out of the NFS mounted directory:\n",
    "```bash\n",
    "cd /\n",
    "```\n",
    "The autofs will unmount the NFS directory after the inactivity period, one minute in our case. Next time the NFS is mounted, it will contain the updated directory tree.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Export NFS from master to rocky VM (exercise)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- On master VM, make sure you can ping rocky91:\n",
    "```bash\n",
    "ping -c 3 rocky91\n",
    "```\n",
    "- If the ping doesn't respond, include the IP address of rocky91 in file ```/etc/hosts```.\n",
    "\n",
    "- Export directory ```/NFS/home``` to rocky91 by following two steps below:\n",
    "Edit file ```/etc/exports``` on master VM and add the line below\n",
    "<pre>\n",
    "/NFS/home  rocky91(rw)\n",
    "</pre>\n",
    "Run command\n",
    "```bash\n",
    "exportfs -a\n",
    "```\n",
    "Verify the exports by running command showmount on master VM:\n",
    "```bash\n",
    "showmount -e master\n",
    "```\n",
    "\n",
    "<hr>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setting NFS client on Redhat (Exercise)\n",
    "\n",
    "On rocky91 VM, install the packages for NFS services:\n",
    "```bash\n",
    "dnf install nfs-utils\n",
    "```\n",
    "Verify that rocky91 can reach out to the RPC on master:\n",
    "```bash\n",
    "rpcinfo -p master\n",
    "```\n",
    "Verify that rocky91 can get the exported NFS directory from master:\n",
    "```bash\n",
    "showmount -e master\n",
    "```\n",
    "On rocky91 VM, create the mount point:\n",
    "```bash\n",
    "mkdir -p /NFS/home\n",
    "```\n",
    "Mount the NFS directory from master VM.\n",
    "```bash\n",
    "mount master:/NFS/home /NFS/home\n",
    "```\n",
    "Verify that the directory is mounted:\n",
    "```bash\n",
    "df -h\n",
    "```\n",
    "\n",
    "Unmount the directory:\n",
    "```bash\n",
    "umount /NFS/home\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "[Linux NFS Overview, FAQ and HOWTO Documents (quite outdated)](http://nfs.sourceforge.net)\n",
    "\n",
    "[NFS on RedHat](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/storage_administration_guide/ch-nfs)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
