{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "# Start/stop services, environment file, job scheduling.\n",
    "\n",
    "- Bootup sequence\n",
    "- Systemd\n",
    "- Service start and stop\n",
    "- Unit files\n",
    "- Environment files\n",
    "- Scheduling jobs with <tt>at</tt> and <tt>cron</tt>\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Linux Bootup and Login Sequence\n",
    "\n",
    "1. BIOS boot-ups; checks peripherals; finds bootable device.\n",
    "\n",
    "2. First sector loaded into RAM and executed-- GRUB prompt appears.\n",
    "\n",
    "3. Kernel loaded from sector list, /boot/vmlinuz-6.1.0-21-amd64; places the appropriate initial RAM disk image, initrd, into RAM.\n",
    "\n",
    "4. Kernel executed; unpacks.\n",
    "\n",
    "5. Kernel initializes hardware.\n",
    "\n",
    "6. Kernel mounts root, /, file system, say /dev/sda1.\n",
    "\n",
    "7. Kernel executes init (Systemd) as PID 1.\n",
    "\n",
    "8. Systemd initiates the units in the default target. The units start the services.\n",
    "\n",
    "9. Among the started services, there are agetty programs on each terminal and the login process.\n",
    "\n",
    "10. login requests user name and password and validates them against /etc/passwd, or NIS maps, or LDAP (depending on PAM settings).\n",
    "\n",
    "11. login starts a shell.\n",
    "\n",
    "12. The shell executes the appropriate startup files (.profile for sh, ksh; .bash_profile for BASH; .cshrc and .login for csh and tcsh).\n",
    "\n",
    "13. The shell prints a prompt and waits for input.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## VM setup for startup scripts. (Exercise)\n",
    " \n",
    "\n",
    "Clone kvm1 to a new NFS server VM host, run01, by executing the command below:\n",
    "```bash\n",
    "virsh shutdown kvm1\n",
    "virt-clone  -o kvm1 -n run01 -f /home/hostadm/KVM/run01.qcow2\n",
    "```\n",
    "Check if the new VM is in the list, start it, then login to its console:\n",
    "```bash\n",
    "virsh list --all\n",
    "virsh start run01\n",
    "virsh console run01\n",
    "```\n",
    "Fix the host name.\n",
    " Replace kvm1 with run01 in /etc/hostname file.\n",
    " Reset the machine ID by running the following commands on kvm3:\n",
    "```bash\n",
    "./vm_id_reset.sh\n",
    "```\n",
    "\n",
    "Reboot the VM:\n",
    "```bash\n",
    "reboot\n",
    "```\n",
    "After reboot, the new VM should come up with the correct host name.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Systemd is the parent of all processes (Exercise)\n",
    "\n",
    "Systemd is the parent of all processes on the system, it is executed by the kernel and is responsible for starting all other processes; it is the parent of all processes whose natural parents have died and it is responsible for reaping those when they die.\n",
    "\n",
    "```bash\n",
    "virsh console run01\n",
    "```\n",
    "Install package psmisc and run command pstree\n",
    "```bash\n",
    "sudo -s\n",
    "apt install psmisc\n",
    "pstree\n",
    "```\n",
    "```{admonition} Output:\n",
    "    systemd─┬─ModemManager───3*[{ModemManager}]\n",
    "            ├─accounts-daemon───3*[{accounts-daemon}]\n",
    "            ├─agetty\n",
    "            ├─atd\n",
    "            ├─cron\n",
    "            ├─dbus-daemon\n",
    "            ├─login───bash───pstree\n",
    "            ├─multipathd───6*[{multipathd}]\n",
    "            ├─networkd-dispat\n",
    "            ├─polkitd───3*[{polkitd}]\n",
    "            ├─rsyslogd───3*[{rsyslogd}]\n",
    "            ├─sshd\n",
    "            ├─systemd───(sd-pam)\n",
    "            ├─systemd-hostnam\n",
    "            ├─systemd-journal\n",
    "            ├─systemd-logind\n",
    "            ├─systemd-network\n",
    "            ├─systemd-resolve\n",
    "            ├─systemd-timesyn───{systemd-timesyn}\n",
    "            ├─systemd-udevd───10*[systemd-udevd]\n",
    "            ├─udisksd───5*[{udisksd}]\n",
    "            └─unattended-upgr───{unattended-upgr}\n",
    "```\n",
    "\n",
    "```bash\n",
    "pstree -p -l\n",
    "```\n",
    "shows the process tree with their PID in the long (non-truncated) format. <tt>/usr/bin/pstree</tt> comes with package psmisc.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Systemd in services startup.\n",
    "\n",
    "![](img/systemd_startup.jpeg)\n",
    "\n",
    "For technical details, read the man pages:\n",
    "```bash\n",
    "man init\n",
    "man systemd\n",
    "man systemctl\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Administrative commands to start/stop services (Exercises)\n",
    "\n",
    "<b>Systemd</b> driven services are available in Ubuntu 18.04 and RedHat 7 and newer \n",
    "\n",
    "Command <tt>systemctl</tt> talks to <tt>systemd</tt>. To see all the services registered with <tt>systemd</tt>, run the following:\n",
    "```bash\n",
    "systemctl list-units --type service\n",
    "```\n",
    "To stop rsyslog services, run\n",
    "```bash\n",
    "systemctl stop rsyslog\n",
    "```\n",
    "To see the status of the service:\n",
    "```bash\n",
    "systemctl status rsyslog\n",
    "```\n",
    "Stop syslog.socket then rsyslog.service:\n",
    "```bash\n",
    "systemctl stop syslog.socket\n",
    "systemctl stop rsyslog.service\n",
    "```\n",
    "To see the status of the service:\n",
    "```bash\n",
    "systemctl status rsyslog\n",
    "```\n",
    "To start the service and see its status:\n",
    "```bash\n",
    "systemctl start rsyslog\n",
    "systemctl status rsyslog\n",
    "```\n",
    "\n",
    "#### Legacy System V services\n",
    "Used to be available on any Linux distro. Now they are provided within Systemd for backward compatibility.\n",
    "The System V (non-event driven) service startup scripts are located in directory <tt>/etc/init.d</tt>. For example to stop and then start cups printing service, use the following\n",
    "\n",
    "```bash\n",
    "apt install cups\n",
    "/etc/init.d/cups stop\n",
    "/etc/init.d/cups start\n",
    "/etc/init.d/cups status\n",
    "```\n",
    "Is the same as\n",
    "```bash\n",
    "service cups stop\n",
    "service cups start\n",
    "service cups status\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## System Run Levels (Legacy System V)\n",
    "This is what used to be on older Linux distros.\n",
    "At bootup, init reads <tt>/etc/inittab</tt> file and executes all scripts for default run level. If the <tt>/etc/inittab</tt> is absent, the default run level is 2.\n",
    "On Unix, there are 7 conventional run levels (0,1,2,3,4,5,6). However, 10 levels are possible (0 -- 9).\n",
    "\n",
    "On Ubuntu and Debian,\n",
    "\n",
    "    Runlevel  0  - is halt.\n",
    "    Runlevel  1  - is single-user.\n",
    "    Runlevels 2-5  are multi-user.\n",
    "    Runlevel  6  - is reboot.\n",
    "\n",
    "On the other Linux systems, such as RedHat,\n",
    " \n",
    "    Runlevel  0 - halt\n",
    "    Runlevel  1 - Single user mode\n",
    "    Runlevel  2 - Multiuser, without NFS (The same as 3, if you do not have networking)\n",
    "    Runlevel  3 - Full multiuser mode\n",
    "    Runlevel  4 - unused\n",
    "    Runlevel  5 - X11\n",
    "    Runlevel  6 - reboot\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Comparison of SysV Runlevels with systemd Targets\n",
    "| Runlevel\t| Target Units | \tDescription \n",
    "| :- | :- | -: \n",
    "|0\t| runlevel0.target, poweroff.target\t| Shut down and power off the system.\n",
    "|1\t|runlevel1.target, rescue.target\t| Set up a rescue shell.\n",
    "|2\t|runlevel2.target, multi-user.target  | Set up a non-graphical multi-user system.\n",
    "|3\t|runlevel3.target, multi-user.target  | Set up a non-graphical multi-user system.\n",
    "|4\t|runlevel4.target, multi-user.target  |\tSet up a non-graphical multi-user system.\n",
    "|5\t|runlevel5.target, graphical.target\t| Set up a graphical multi-user system.\n",
    "|6\t|runlevel6.target, reboot.target\t| Shut down and reboot the system.\n",
    "\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Working with Systemd targets (Exercises)\n",
    "\n",
    "Viewing the Default Target:\n",
    "```bash\n",
    "systemctl get-default\n",
    "```\n",
    "Viewing the Current Target\n",
    "```bash\n",
    "systemctl list-units --type target\n",
    "```\n",
    "Changing the Default Target\n",
    "```bash\n",
    "systemctl set-default multi-user.target\n",
    "```\n",
    "Reboot. Run commands\n",
    "```bash\n",
    "systemctl get-default\n",
    "systemctl list-units --type target\n",
    "```\n",
    "Set password for root:\n",
    "```bash\n",
    "sudo -s\n",
    "passwd\n",
    "```\n",
    "Changing the Current Target\n",
    "```bash\n",
    "systemctl isolate graphical.target\n",
    "```\n",
    "Check the Target units\n",
    "```bash\n",
    "systemctl list-units --type target\n",
    "```\n",
    "Changing to Rescue Mode\n",
    "```bash\n",
    "systemctl rescue\n",
    "```\n",
    "Check the Target units\n",
    "```bash\n",
    "systemctl list-units --type target\n",
    "```\n",
    "Changing to Emergency Mode\n",
    "```bash\n",
    "systemctl emergency\n",
    "```\n",
    "Check the Target units\n",
    "```bash\n",
    "systemctl list-units --type target\n",
    "```\n",
    "Run command <tt>pstree</tt> to see the number of processes running.\n",
    "\n",
    "You can see the target dependencies on the other targets and services with command ```systemctl list-dependencies <target name>```.\n",
    "For example, for the graphical target:\n",
    "```bash\n",
    "systemctl list-dependencies graphical.target\n",
    "```\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding service to systemd startup (Exercise)\n",
    "\n",
    "In directory <tt>/home/hostadm</tt>, create a shell script file, <tt>test.sh</tt>:\n",
    "```{admonition} File content:\n",
    "    #!/bin/bash\n",
    "    echo \"current date/time is $(/bin/date)\" >> /home/hostadm/timecheck.txt\n",
    "```\n",
    "\n",
    "Make the script executable\n",
    "```bash\n",
    "chmod 755  /home/hostadm/test.sh\n",
    "```\n",
    "\n",
    "In directory <tt>/lib/systemd/system</tt>, create unit service file, <tt>test.service</tt>:\n",
    "```{admonition} File content:\n",
    "    [Unit]\n",
    "    Description=test startup\n",
    "\n",
    "    [Service]\n",
    "    Type=simple\n",
    "    ExecStart=/home/hostadm/test.sh\n",
    "\n",
    "    [Install]\n",
    "    WantedBy=default.target\n",
    "```\n",
    "\n",
    "Enable service test in systemd:\n",
    "```bash\n",
    "systemctl daemon-reload\n",
    "systemctl enable test\n",
    "```\n",
    "Run commands\n",
    "```bash\n",
    "systemctl start test\n",
    "systemctl status test\n",
    "```\n",
    "Check if file <tt>/home/hostadm/timecheck.txt</tt> has been updated.\n",
    "Reboot the VM. Run command\n",
    "```bash\n",
    "systemctl status test\n",
    "```\n",
    "Check if file <tt>/home/hostadm/timecheck.txt</tt> has been updated.\n",
    "\n",
    "<hr>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding stop script to the unit (Exercise)\n",
    "\n",
    "In directory <tt>/home/hostadm</tt>, create another shell script file, <tt>stop.sh</tt>:\n",
    "\n",
    "```{admonition} script file:\n",
    "    #!/bin/bash\n",
    "    echo STOP >> /home/hostadm/timecheck.txt\n",
    "```\n",
    "Make the script executable\n",
    "```bash\n",
    "chmod 755  /home/hostadm/stop.sh\n",
    "```\n",
    "In directory <tt>/lib/systemd/system</tt>, modify the unit service file, <tt>test.service</tt> by adding two lines in the [Service] block:\n",
    "```{admonition} test.service:\n",
    "    [Unit]\n",
    "    Description=test startup\n",
    "\n",
    "    [Service]\n",
    "    Type=simple\n",
    "    ExecStart=/home/hostadm/test.sh\n",
    "    RemainAfterExit=true\n",
    "    ExecStop=/home/hostadm/stop.sh \n",
    "\n",
    "    [Install]\n",
    "    WantedBy=default.target\n",
    "```\n",
    "Reload systemd:\n",
    "```bash\n",
    "systemctl daemon-reload\n",
    "```\n",
    "\n",
    "Run commands\n",
    "```bash\n",
    "systemctl stop test\n",
    "systemctl status test\n",
    "```\n",
    "Check if file <tt>/home/hostadm/timecheck.txt</tt> has been updated with entry \"STOP\", generated by the <tt>stop.sh</tt> script.\n",
    "<hr>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## User settings at login.\n",
    "\n",
    "When a user logins, getty gives him SHELL.\n",
    "\n",
    "In case of /bin/bash, the following initialization/configuration scripts are executed:\n",
    "\n",
    "| /etc/profile\t| System wide initialization file. Runs at log in.\n",
    "| :--            |  -:    |\n",
    "|~/.bash_profile  |\tExecuted automatically after /etc/profile\n",
    "|~/.bash_login\t| If ~/.bash_profile is absent, the script is executed after /etc/profile, otherwise, ignored.\n",
    "|~/.profile\t| If both ~/.bash_profile and ~/.bash_login are absent, the script is executed after /etc/profile, otherwise, ignored.\n",
    "|~/.bashrc\t | It is called from ~/.bash_profile at startup. An interactive shell that is not a login shell also reads ~/.bashrc .\n",
    "|~/.bash_logout\t| Executed automatically during log out\n",
    "\n",
    "\n",
    "When you need to specify environment variables, for example PATH, you can place them in /etc/profile for all users on the system, or in ~/.bashrc for the specific user.\n",
    "\n",
    "When the user logs out, control returns to init, which wakes up and spawns a new getty on the terminal port.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Login scripts  (Exercise).\n",
    "\n",
    "Complete the exercises below on run01 VM\n",
    "\n",
    "In a user home directory, there should be scripts .profile and .bashrc.\n",
    "Create a new user account, for example jerry:\n",
    "```bash\n",
    "useradd -m -s /bin/bash jerry\n",
    "passwd jerry\n",
    "```\n",
    "In file .profile, put entry\n",
    "```{admonition} file content\n",
    "echo PROFILE\n",
    "```\n",
    "\n",
    "In file .bashrc, put entry\n",
    "```{admonition} file content\n",
    "echo BASHRC\n",
    "```\n",
    "\n",
    "Logout and login as user jerry.\n",
    "You can also switch to user jerry from the root:\n",
    "```bash\n",
    "su - jerry\n",
    "```\n",
    "\n",
    "Notice PROFILE in the login prompt. \n",
    "\n",
    "Start a new shell,\n",
    "```bash\n",
    "/bin/bash\n",
    "```\n",
    "notice BASHRC in the new shell prompt.\n",
    "\n",
    "Logout from user jerry:\n",
    "```bash\n",
    "exit\n",
    "```\n",
    "\n",
    "<hr>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## One time scheduled jobs: at\n",
    "To schedule a job to run once at a particular time, use command at time_to_run, for example, to run at 8:40 am:\n",
    "\n",
    "```bash\n",
    "at 0840\n",
    "```\n",
    "Then type-in commands and finish with ^D\n",
    "\n",
    "Time format examples:\n",
    "```bash\n",
    "at 1825 Mar 4\n",
    "at now + 1 minute\n",
    "at now + 1 hour\n",
    "at now + 1 day\n",
    "```\n",
    "\n",
    "To run an executable file or a script:\n",
    "```bash\n",
    "at -f filename time_to_run\n",
    "```\n",
    "For example,\n",
    "```bash\n",
    "at -f /home/jerry/script.sh 2030\n",
    "at -f /home/jerry/script.sh 11am Mar 30\n",
    "```\n",
    "Command at puts a scheduled job in a queue in <tt>/var/spool/at/</tt>; daemon <tt>/usr/sbin/atd</tt> checks for queued jobs in that directory and runs them.\n",
    "\n",
    "To check scheduled job status, run\n",
    "```bash\n",
    "atq\n",
    "```\n",
    "To delete scheduled job, run\n",
    "```bash\n",
    "atrm\n",
    "```\n",
    "\n",
    "Permssions on using at:\n",
    "\n",
    "If <tt>/etc/at.allow</tt> does not exist, <tt>/etc/at.deny</tt> is checked, every user name not mentioned in it is then allowed to use at.\n",
    "If neither exists, only the superuser is allowed use of at.\n",
    "An empty <tt>/etc/at.deny</tt> means that every user is allowed use these commands.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Scheduled periodical jobs: cron.\n",
    "\n",
    "To schedule jobs to execute repetitively at regular intervals, use cron. Daemon crond runs every minute and searches /var/spool/cron for crontab files and checks /etc/crontab and /etc/cron.d.\n",
    "/etc/crontab:\n",
    "\n",
    "```{admonition} cron file content\n",
    "    SHELL=/bin/sh\n",
    "    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n",
    "    # m h dom mon dow user  command\n",
    "    17 *    * * *   root    run-parts --report /etc/cron.hourly\n",
    "    25 6    * * *   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.daily\n",
    "    47 6    * * 0   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.weekly\n",
    "    52 6    1 * *   root    test -x /usr/sbin/anacron || run-parts --report /etc/cron.monthly\n",
    "```\n",
    "\n",
    "Format: (time) (user) (executable)\n",
    "time: minute (0-59), hour(0-23), day of the month(1-31), month(1-12), week day (0-6) starting with Sun.\n",
    "Example:\n",
    "\n",
    "```{admonition} cron file content:\n",
    "    25 10 * * * root  /root/scheduled.sh   # runs /root/scheduled.sh every day at 10:25\n",
    "    25 10 * * 6 root  /root/scheduled.sh   # runs every Sat. at 10:25\n",
    "    */5 * * * 6 root  /root/scheduled.sh   # runs every 5 min on Sat.\n",
    "```\n",
    "\n",
    "On systems that don't run continuously, such as desktops and laptops, a scheduled in cron job may miss its time to run. Another scheduler, anacron, can be used to run periodically and when the system boots up.\n",
    "/etc/anacrontab:\n",
    "\n",
    "\n",
    "```{admonition} anacron file content\n",
    "    SHELL=/bin/sh\n",
    "    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin\n",
    "\n",
    "    # These replace cron's entries\n",
    "    1       5       cron.daily       nice run-parts --report /etc/cron.daily\n",
    "    7       10      cron.weekly      nice run-parts --report /etc/cron.weekly\n",
    "    @monthly        15      cron.monthly nice run-parts --report /etc/cron.monthly\n",
    "```\n",
    "Format: (period in days) (delay in minutes) (job-identifier) (command)\n",
    "Usually, anacron runs at system startup and daily at 7:30 a.m. by cron.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Scheduling at and cron. (Exercises).\n",
    "Complete the exercises below on run01 VM\n",
    "\n",
    "Install package at:\n",
    "```bash\n",
    "apt install at\n",
    "```\n",
    "As user hostadm, Create script, <tt>mem.sh</tt>, to check memory status:\n",
    "```{admonition} file content\n",
    "    #!/bin/bash\n",
    "    # Checks memory status through cron\n",
    "\n",
    "    of=/home/hostadm/mem.out\n",
    "    dt=$(date)\n",
    "\n",
    "    echo \"Memory status (in MB) on $dt:\" >> $of\n",
    "    free -m >> $of\n",
    "    echo \"------------------\" >> $of\n",
    "\n",
    "```\n",
    "Make it executable\n",
    "```bash\n",
    "chmod 755 mem.sh\n",
    "```\n",
    "and run through at:\n",
    "```bash\n",
    "at -f mem.sh now + 1 minute\n",
    "```\n",
    "Run <tt>atq</tt> to make sure the job is scheduled. In a minute, check content of a new file, <tt>mem.out</tt>; run <tt>atq</tt> again.\n",
    "\n",
    "Remove file <tt>mem.out</tt>. Add the following entry in <tt>/etc/crontab</tt> below the other scheduled tasks:\n",
    "```{admonition} file content\n",
    "    */2 * * * *  root  /home/hostadm/mem.sh\n",
    "```\n",
    "Check if the content of <tt>mem.out</tt> is updated every 2 minutes.\n",
    "\n",
    "<hr>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References on systemd and cron\n",
    "\n",
    "[Managing Services with systemd (RedHat documentation)](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/chap-managing_services_with_systemd)\n",
    "\n",
    "[Cron (Wikipedia)](https://en.wikipedia.org/wiki/Cron)\n",
    "\n",
    "[Crontab calculator](https://crontab.guru/)\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
}
