Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédente | ||
elearning:workbooks:centos:8:junior:l116 [2021/06/14 16:12] – admin | elearning:workbooks:centos:8:junior:l116 [2024/09/12 09:18] (Version actuelle) – admin | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
~~PDF: | ~~PDF: | ||
- | Version : **2021.01** | + | Version : **2024.01** |
Dernière mise-à-jour : ~~LASTMOD~~ | Dernière mise-à-jour : ~~LASTMOD~~ | ||
Ligne 39: | Ligne 39: | ||
* Processus de Démarrage du Noyau Linux | * Processus de Démarrage du Noyau Linux | ||
* Processus Init | * Processus Init | ||
- | * Démarrer RHEL/CentOS 8 | + | * Systemd |
- | * La Commande systemctl | + | * LAB #1 - La Commande systemctl |
- | * Fichiers de Configuration | + | * LAB #2 - Fichiers de Configuration |
- | * La Commande systemd-analyze | + | * 2.1 - Fichiers de Configuration par Défaut |
- | * Gestion des Services | + | * 2.2 - Surchargement des Fichiers de Configuration par Défaut |
+ | * LAB #3 - La Commande systemd-analyze | ||
+ | * LAB #4 - Les Cibles Systemd | ||
+ | * 4.1 - Contrôler les dépendances d'une Cible | ||
+ | * 4.2 - La Cible par Défaut | ||
+ | * LAB #5 - Gestion des Services | ||
+ | * 5.1 - Gestion des Instances Uniques | ||
+ | * 5.2 - Gestion d' | ||
+ | * 5.3 - Interdire la Modification du Statut d'un Service | ||
* Arrêt Système du Système | * Arrêt Système du Système | ||
* La Commande shutdown | * La Commande shutdown | ||
Ligne 75: | Ligne 83: | ||
* Lancer le **Charger de Démarrage** du système d' | * Lancer le **Charger de Démarrage** du système d' | ||
- | ===Charger | + | ===Chargeur |
- | La première partie du Charger | + | La première partie du Chargeur |
* 446 octets pour le Charger de Démarrage, | * 446 octets pour le Charger de Démarrage, | ||
Ligne 96: | Ligne 104: | ||
<WRAP center round important 60%> | <WRAP center round important 60%> | ||
- | **Important** : L'UEFI gère parfaitement | + | **Important** : L'UEFI gère les **SSD** (//Solid State Drives//) qui utilisent le standard **NVMe** (// |
</ | </ | ||
Ligne 105: | Ligne 113: | ||
=====Gestionnaires de Démarrage===== | =====Gestionnaires de Démarrage===== | ||
- | Des gestionnaires d' | + | ====GRUB 2==== |
- | + | ||
- | * GRUB (Grand Unified Boot Loader) | + | |
- | + | ||
- | Cependant il en existe d' | + | |
- | + | ||
- | * LILO (LInux LOader) | + | |
- | * %%SysLinux%% | + | |
- | * %%LoadLin%% | + | |
- | * ... | + | |
- | + | ||
- | ====GRUB 2 sous RHEL/CentOS 8==== | + | |
GRUB 2 est une ré-écriture complète de GRUB Legacy. Il apporte des améliorations, | GRUB 2 est une ré-écriture complète de GRUB Legacy. Il apporte des améliorations, | ||
Ligne 320: | Ligne 317: | ||
</ | </ | ||
- | Prenons le cas des paramètres de Grub Legacy et comparons-les aux paramètres de GRUB 2 : | + | Notez que ce fichier ne doit pas être modifié manuellement. En effet, il est généré par la commande **grub2-mkconfig**. La commande grub2-mkconfig prend en argument l' |
- | + | ||
- | ^ Grub Legacy ^ GRUB 2 ^ | + | |
- | | title | Menuentry | | + | |
- | | root (hd0,0) | set root=hd(0, | + | |
- | | kernel | linux | | + | |
- | | initrd | initrd | | + | |
- | | lock | Ce paramètre n' | + | |
- | | rootnoverify (hd0,1) | Ce paramètre n' | + | |
- | + | ||
- | Notez que ce fichier ne doit pas être modifié manuellement. En effet, il est généré par la commande **grub2-mkconfig** | + | |
* grub2-mkconfig -o / | * grub2-mkconfig -o / | ||
Ligne 361: | Ligne 348: | ||
GRUB_ENABLE_BLSCFG=true | GRUB_ENABLE_BLSCFG=true | ||
</ | </ | ||
- | |||
<WRAP center round important 60%> | <WRAP center round important 60%> | ||
- | **Important** : Notez que toute modification de ce fichier nécessite l' | + | **Important** : Notez que toute modification de ce fichier nécessite l' |
</ | </ | ||
Ligne 370: | Ligne 356: | ||
^ Directive | ^ Directive | ||
- | | GRUB_DEFAULT | Entrée du menu sélectionner par défaut | | ||
| GRUB_TIMEOUT | Durée de l' | | GRUB_TIMEOUT | Durée de l' | ||
| GRUB_DISTRIBUTOR | Ligne de commande qui génère le texte de l' | | GRUB_DISTRIBUTOR | Ligne de commande qui génère le texte de l' | ||
- | | GRUB_CMDLINE_LINUX_DEFAULT | + | | GRUB_DEFAULT |
+ | | GRUB_DISABLE_SUBMENU | Active ou désactive les sous-menus de GRUB2 | | ||
+ | | GRUB_TERMINAL_OUTPUT | Spécifie | ||
| GRUB_CMDLINE_LINUX | Paramètres passés au noyau peu importe le type de démarrage | | | GRUB_CMDLINE_LINUX | Paramètres passés au noyau peu importe le type de démarrage | | ||
- | | GRUB_TERMINAL | + | | GRUB_DISABLE_RECOVERY |
- | | GRUB_GFXMODE | Indique la résolution utilisée lors d'un démarrage graphique | | + | | GRUB_BLSCFG |
- | | GRUB_DISABLE_LINUX_UUID | Si **true**, cette directive empêche l' | + | |
- | | GRUB_DISABLE_LINUX_RECOVERY | Si **true**, cette directive empêche | + | |
- | | GRUB_INIT_TUNE | + | |
- | | GRUB_BADRAM | Permet | + | |
===Les fichiers du répertoire / | ===Les fichiers du répertoire / | ||
Ligne 412: | Ligne 395: | ||
* Ces deux fichiers sont fournis en tant que modèles à personnaliser. | * Ces deux fichiers sont fournis en tant que modèles à personnaliser. | ||
- | ===Configurer l' | + | ===Le Fichier / |
- | La configuration de l'authentification de GRUB 2 est automatisée | + | Le fichier **/ |
< | < | ||
- | [root@centos8 ~]# cat / | + | [root@centos8 ~]# cat / |
- | #!/bin/sh -e | + | # GRUB Environment Block |
- | cat << EOF | + | |
- | if [ -f \${prefix}/ | + | |
- | source \${prefix}/ | + | |
- | if [ -n " | + | |
- | set superusers=" | + | |
- | export superusers | + | |
- | password_pbkdf2 root \${GRUB2_PASSWORD} | + | |
- | fi | + | |
- | fi | + | |
- | EOF | + | |
- | </ | + | |
- | + | ||
- | Ce script est évidement présent dans le fichier **grub.cfg** : | + | |
- | + | ||
- | < | + | |
- | ... | + | |
- | ### BEGIN / | + | |
- | if [ -f ${prefix}/ | + | |
- | source ${prefix}/ | + | |
- | if [ -n " | + | |
- | set superusers=" | + | |
- | export superusers | + | |
- | password_pbkdf2 root ${GRUB2_PASSWORD} | + | |
- | fi | + | |
- | fi | + | |
- | ### END / | + | |
- | ... | + | |
- | </ | + | |
- | + | ||
- | Ce script : | + | |
- | + | ||
- | * teste si le fichier **/ | + | |
- | * teste si la variable $GRUB2_PASSWORD est fixée puis si c'est le cas, | + | |
- | * assigne le mot de passe à root. | + | |
- | + | ||
- | Pour créer le contenu du fichier **/ | + | |
- | + | ||
- | < | + | |
- | [root@centos8 ~]# grub2-setpassword | + | |
- | Enter password: pass123 | + | |
- | Confirm password: pass123 | + | |
- | </ | + | |
- | + | ||
- | Consultez maintenant le fichier **/ | + | |
- | + | ||
- | < | + | |
- | [root@centos8 ~]# cat / | + | |
- | GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.2BD9CC45BAE9738C9C916AEB734F52998B32C062C4F02101DB28BB057F8D95075900B4C8122C3B5E17C392E0B89F162520605BC19D2E4FF4D7FBA25FE98A935E. | + | |
- | E442FADF439D0A0FB3692E463B91B6BDD1978DD0A83ED1FF55B090C490AE52EA85FAD2A45634EC5C702A88DD556179998ED3F6FBD803CABBD93E88A10A51362F | + | |
- | </ | + | |
- | + | ||
- | <WRAP center round todo 60%> | + | |
- | **A faire** : Redémarrez votre VM. Appuyez sur la touche **e** au début du processus de démarrage. Constatez que GRUB 2 demande un nom d' | + | |
- | </ | + | |
- | + | ||
- | Pour pouvoir protéger le démarrage du système, il convient d' | + | |
- | + | ||
- | < | + | |
- | [root@centos7 ~]# cat / | + | |
- | ... | + | |
- | ### BEGIN / | + | |
- | menuentry ' | + | |
- | load_video | + | |
- | set gfxpayload=keep | + | |
- | insmod gzio | + | |
- | insmod part_msdos | + | |
- | insmod xfs | + | |
- | set root=' | + | |
- | if [ x$feature_platform_search_hint = xy ]; then | + | |
- | search --no-floppy --fs-uuid --set=root --hint-bios=hd0, | + | |
- | else | + | |
- | search --no-floppy --fs-uuid --set=root 2d947276-66e8-41f4-8475-b64b67d7a249 | + | |
- | fi | + | |
- | linux16 / | + | |
- | initrd16 / | + | |
- | } | + | |
- | ... | + | |
- | </ | + | |
- | + | ||
- | < | + | |
- | [root@centos7 ~]# vi / | + | |
- | ... | + | |
- | ### BEGIN / | + | |
- | menuentry ' | + | |
- | load_video | + | |
- | set gfxpayload=keep | + | |
- | insmod gzio | + | |
- | insmod part_msdos | + | |
- | insmod xfs | + | |
- | set root=' | + | |
- | if [ x$feature_platform_search_hint = xy ]; then | + | |
- | search --no-floppy --fs-uuid --set=root --hint-bios=hd0, | + | |
- | else | + | |
- | search --no-floppy --fs-uuid --set=root 2d947276-66e8-41f4-8475-b64b67d7a249 | + | |
- | fi | + | |
- | linux16 / | + | |
- | initrd16 / | + | |
- | } | + | |
- | ... | + | |
- | </ | + | |
- | + | ||
- | [root@centos8 ~]# grubby --info DEFAULT | + | |
- | index=0 | + | |
- | kernel="/ | + | |
- | args=" | + | |
- | root=" | + | |
- | initrd="/ | + | |
- | title=" | + | |
- | id=" | + | |
- | + | ||
- | [root@centos8 ~]# grub2-editenv - list | + | |
saved_entry=de79af4f226d480fa7d3fec4cabbf97a-4.18.0-240.22.1.el8_3.x86_64 | saved_entry=de79af4f226d480fa7d3fec4cabbf97a-4.18.0-240.22.1.el8_3.x86_64 | ||
kernelopts=root=UUID=4c0cc28c-0d59-45be-bd73-d292b80be33c ro crashkernel=auto resume=UUID=c8bb3f47-d67f-4b21-b781-766899dc83d4 rhgb quiet | kernelopts=root=UUID=4c0cc28c-0d59-45be-bd73-d292b80be33c ro crashkernel=auto resume=UUID=c8bb3f47-d67f-4b21-b781-766899dc83d4 rhgb quiet | ||
- | boot_success=0 | + | boot_success=1 |
boot_indeterminate=0 | boot_indeterminate=0 | ||
- | + | ########################################################################################################################################## | |
- | <WRAP center round todo 60%> | + | ########################################################################################################################################## |
- | **A faire** : Redémarrez votre VM. Constatez que GRUB 2 demande un nom d' | + | ########################################################################################################################################## |
- | </WRAP> | + | ########################################################################################################################################## |
+ | ########################################################################################################################################## | ||
+ | ############################################################ | ||
+ | </code> | ||
===Modifier la Configuration de GRUB 2 en Ligne de Commande=== | ===Modifier la Configuration de GRUB 2 en Ligne de Commande=== | ||
Ligne 553: | Ligne 427: | ||
* **Crtl-X** : démarrer avec la configuration modifiée, | * **Crtl-X** : démarrer avec la configuration modifiée, | ||
* **echap** : abandonner les modifications et retourner à l' | * **echap** : abandonner les modifications et retourner à l' | ||
- | |||
- | <WRAP center round important 60%> | ||
- | **Important** : Certaines distributions, | ||
- | </ | ||
====Chargeurs de Démarrages Alternatifs==== | ====Chargeurs de Démarrages Alternatifs==== | ||
Ligne 616: | Ligne 486: | ||
tmp.iso | tmp.iso | ||
vg0_backup | vg0_backup | ||
+ | |||
+ | [root@centos8 tmp]# mv custom custom.gz | ||
+ | |||
+ | [root@centos8 tmp]# gunzip custom.gz | ||
+ | |||
[root@centos8 tmp]# mkdir initramfs | [root@centos8 tmp]# mkdir initramfs | ||
+ | |||
[root@centos8 tmp]# cd initramfs | [root@centos8 tmp]# cd initramfs | ||
+ | |||
[root@centos8 initramfs]# cpio -cid -I ../custom | [root@centos8 initramfs]# cpio -cid -I ../custom | ||
216 blocks | 216 blocks | ||
[root@centos8 initramfs]# ls | [root@centos8 initramfs]# ls | ||
- | early_cpio | + | bin dev etc init lib lib64 proc root run sbin shutdown |
</ | </ | ||
Ligne 754: | Ligne 631: | ||
* **halt.target** - arrête le système. | * **halt.target** - arrête le système. | ||
* **poweroff.target** - arrête le système et coupe le courant. | * **poweroff.target** - arrête le système et coupe le courant. | ||
+ | * **shutdown.target** - arrête le système. | ||
* **rescue.target** - démarre le système en mode single-user (seul root peut s'y connecter). Tous les systèmes de fichiers sont montés mais le réseau n'est pas démarré. | * **rescue.target** - démarre le système en mode single-user (seul root peut s'y connecter). Tous les systèmes de fichiers sont montés mais le réseau n'est pas démarré. | ||
* **emergency.target** - démarre le système en mode single-user (seul root peut s'y connecter). Uniquement le système de fichiers racine est monté en mode lecture seule. Le réseau n'est pas démarré. | * **emergency.target** - démarre le système en mode single-user (seul root peut s'y connecter). Uniquement le système de fichiers racine est monté en mode lecture seule. Le réseau n'est pas démarré. | ||
Ligne 789: | Ligne 667: | ||
</ | </ | ||
- | ====La Commande systemctl==== | + | ====LAB #1 - La Commande systemctl==== |
Pour visualiser la liste des Unités, il convient d' | Pour visualiser la liste des Unités, il convient d' | ||
Ligne 1013: | Ligne 891: | ||
Dans la colonne STATE on voit les mots **static** et **generated**. | Dans la colonne STATE on voit les mots **static** et **generated**. | ||
- | ===STATE = static=== | + | * STATE = static |
+ | * Ceci implique que l' | ||
- | Ceci implique que l' | + | * STATE = generated |
- | + | | |
- | ===STATE = generated=== | + | |
- | + | ||
- | Ceci implique que le fichier a été généré automatiquement en utilisant les informations dans le fichier **/ | + | |
< | < | ||
Ligne 1047: | Ligne 923: | ||
-rwxr-xr-x. 1 root root 17024 Apr 7 16:56 systemd-veritysetup-generator | -rwxr-xr-x. 1 root root 17024 Apr 7 16:56 systemd-veritysetup-generator | ||
</ | </ | ||
- | |||
- | ===Options de la Commande systemctl=== | ||
Les options de la commande **systemctl** sont : | Les options de la commande **systemctl** sont : | ||
Ligne 1114: | Ligne 988: | ||
</ | </ | ||
- | ====Fichiers de Configuration==== | + | ====LAB #2 - Fichiers de Configuration==== |
- | ===Fichiers de Configuration par Défaut=== | + | ===2.1 - Fichiers de Configuration par Défaut=== |
Les fichiers de configuration des Cibles et fichiers de configuration des Unités installés par des paquets se trouvent dans le répertoire **/ | Les fichiers de configuration des Cibles et fichiers de configuration des Unités installés par des paquets se trouvent dans le répertoire **/ | ||
Ligne 1205: | Ligne 1079: | ||
</ | </ | ||
- | ===Surchargement des Fichiers de Configuration par Défaut=== | + | Prenons le cas du service **sshd** qui est configuré par le fichier **/ |
+ | |||
+ | < | ||
+ | [root@centos8 ~]# cat / | ||
+ | [Unit] | ||
+ | Description=OpenSSH server daemon | ||
+ | Documentation=man:sshd(8) man: | ||
+ | After=network.target sshd-keygen.target | ||
+ | Wants=sshd-keygen.target | ||
+ | |||
+ | [Service] | ||
+ | Type=notify | ||
+ | EnvironmentFile=-/ | ||
+ | EnvironmentFile=-/ | ||
+ | ExecStart=/ | ||
+ | ExecReload=/ | ||
+ | KillMode=process | ||
+ | Restart=on-failure | ||
+ | RestartSec=42s | ||
+ | |||
+ | [Install] | ||
+ | WantedBy=multi-user.target | ||
+ | </ | ||
+ | |||
+ | Dans le fichier on peut noter la présence des lignes suivantes dans la section **[Unit]** : | ||
+ | |||
+ | * **Description=OpenSSH server daemon**, | ||
+ | * Cette directive est utilisée pour donner une courte description des fonctionnalités de l' | ||
+ | * **Documentation=man: | ||
+ | * Cette directive stipule les chapitres des manuels et les URLs contenant de l' | ||
+ | * **After=network.target sshd-keygen.target**, | ||
+ | * Cette directive indique les cibles qui devraient être atteintes et les Unités qui devraient être démarrées avant l' | ||
+ | * **Wants=sshd-keygen.target**, | ||
+ | * Cette directive stipule une dépendance douce. Autrement dit, Systemd essayera de démarrer l' | ||
+ | |||
+ | Dans le fichier on peut aussi noter la présence des lignes suivantes dans la section **[Service]** : | ||
+ | |||
+ | * **Type=notify**, | ||
+ | * Cette directive indique que le service informera Systemd quand son démarrage a terminé, | ||
+ | * **ExecStart=/ | ||
+ | * Cette directive définit l' | ||
+ | * **ExecReload=/ | ||
+ | * Cette directive indique la commande necéssaire pour redémarrer le service, | ||
+ | * **KillMode=process**, | ||
+ | * Cette directive indique comment les processus du service doivent être arrêtés. La valeur de **process** implique l' | ||
+ | * **Restart=on-failure**, | ||
+ | * Cette ligne indique que le service doit être re-démarré en cas d' | ||
+ | * **RestartSec=42s**, | ||
+ | * Cette directive stipule le temps d' | ||
+ | |||
+ | Dernièrement on note la présence de la ligne suivante dans la section **[Install]** : | ||
+ | |||
+ | * **WantedBy=multi-user.target**, | ||
+ | * Cette directive indique la Cible dans laquelle le service doit être démarré. La présence de cette directive crée un lien symbolique dans le répertoire **/ | ||
+ | |||
+ | Pour consulter **l' | ||
+ | |||
+ | < | ||
+ | [root@centos8 ~]# systemctl show sshd | ||
+ | Type=notify | ||
+ | Restart=on-failure | ||
+ | NotifyAccess=main | ||
+ | RestartUSec=42s | ||
+ | TimeoutStartUSec=1min 30s | ||
+ | TimeoutStopUSec=1min 30s | ||
+ | RuntimeMaxUSec=infinity | ||
+ | WatchdogUSec=0 | ||
+ | WatchdogTimestamp=Thu 2021-06-03 15:09:54 EDT | ||
+ | WatchdogTimestampMonotonic=12502561 | ||
+ | PermissionsStartOnly=no | ||
+ | RootDirectoryStartOnly=no | ||
+ | RemainAfterExit=no | ||
+ | GuessMainPID=yes | ||
+ | MainPID=902 | ||
+ | ControlPID=0 | ||
+ | FileDescriptorStoreMax=0 | ||
+ | NFileDescriptorStore=0 | ||
+ | StatusErrno=0 | ||
+ | Result=success | ||
+ | UID=[not set] | ||
+ | GID=[not set] | ||
+ | NRestarts=0 | ||
+ | ExecMainStartTimestamp=Thu 2021-06-03 15:09:54 EDT | ||
+ | ExecMainStartTimestampMonotonic=12446178 | ||
+ | ExecMainExitTimestampMonotonic=0 | ||
+ | ExecMainPID=902 | ||
+ | ExecMainCode=0 | ||
+ | ExecMainStatus=0 | ||
+ | ExecStart={ path=/ | ||
+ | ExecReload={ path=/ | ||
+ | Slice=system.slice | ||
+ | ControlGroup=/ | ||
+ | MemoryCurrent=6270976 | ||
+ | CPUUsageNSec=[not set] | ||
+ | EffectiveCPUs= | ||
+ | EffectiveMemoryNodes= | ||
+ | TasksCurrent=1 | ||
+ | IPIngressBytes=18446744073709551615 | ||
+ | IPIngressPackets=18446744073709551615 | ||
+ | IPEgressBytes=18446744073709551615 | ||
+ | IPEgressPackets=18446744073709551615 | ||
+ | Delegate=no | ||
+ | CPUAccounting=no | ||
+ | CPUWeight=[not set] | ||
+ | StartupCPUWeight=[not set] | ||
+ | CPUShares=[not set] | ||
+ | StartupCPUShares=[not set] | ||
+ | CPUQuotaPerSecUSec=infinity | ||
+ | CPUQuotaPeriodUSec=infinity | ||
+ | AllowedCPUs= | ||
+ | AllowedMemoryNodes= | ||
+ | IOAccounting=no | ||
+ | IOWeight=[not set] | ||
+ | StartupIOWeight=[not set] | ||
+ | BlockIOAccounting=no | ||
+ | BlockIOWeight=[not set] | ||
+ | lines 1-57 | ||
+ | </ | ||
+ | |||
+ | Pour consulter la liste des dépendances d'une Unité, il convient d' | ||
+ | |||
+ | < | ||
+ | [root@centos8 ~]# systemctl list-dependencies sshd.service | ||
+ | sshd.service | ||
+ | ● ├─system.slice | ||
+ | ● ├─sshd-keygen.target | ||
+ | ● │ ├─sshd-keygen@ecdsa.service | ||
+ | ● │ ├─sshd-keygen@ed25519.service | ||
+ | ● │ └─sshd-keygen@rsa.service | ||
+ | ● └─sysinit.target | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● | ||
+ | ● │ ├─-.mount | ||
+ | ● │ ├─boot.mount | ||
+ | ● │ └─systemd-remount-fs.service | ||
+ | ● | ||
+ | ● | ||
+ | </ | ||
+ | |||
+ | ===2.2 - Surchargement des Fichiers de Configuration par Défaut=== | ||
Les fichiers de configuration par défaut peuvent aussi être surchargés par des fichiers dans d' | Les fichiers de configuration par défaut peuvent aussi être surchargés par des fichiers dans d' | ||
Ligne 1242: | Ligne 1292: | ||
</ | </ | ||
- | ====La Commande systemd-analyze==== | + | ====LAB #3 - La Commande systemd-analyze==== |
Pour avoir une évaluation du temps de démarrage, il convient d' | Pour avoir une évaluation du temps de démarrage, il convient d' | ||
Ligne 1316: | Ligne 1366: | ||
</ | </ | ||
- | ===Options | + | L' |
+ | |||
+ | < | ||
+ | [root@centos8 ~]# systemd-analyze critical-chain sshd.service | ||
+ | The time after the unit is active or started is printed after the " | ||
+ | The time the unit takes to start is printed after the " | ||
+ | |||
+ | sshd.service +56ms | ||
+ | └─network.target @3.799s | ||
+ | └─NetworkManager.service @3.719s +77ms | ||
+ | └─network-pre.target @3.718s | ||
+ | └─firewalld.service @3.004s +713ms | ||
+ | └─polkit.service @2.397s +605ms | ||
+ | └─basic.target @2.392s | ||
+ | └─sockets.target @2.392s | ||
+ | └─sssd-kcm.socket @2.391s | ||
+ | └─sysinit.target @2.379s | ||
+ | └─systemd-update-utmp.service @2.370s +8ms | ||
+ | └─auditd.service @2.317s +52ms | ||
+ | └─systemd-tmpfiles-setup.service @2.118s +196ms | ||
+ | └─import-state.service @2.070s +46ms | ||
+ | └─local-fs.target @2.069s | ||
+ | └─boot.mount @2.006s +62ms | ||
+ | └─systemd-fsck@dev-disk-by\x2duuid-2ae4c035\x2d9244\x2d458c\x2d82c5\x2da49ae169cdb6.service @1.943s +54ms | ||
+ | └─local-fs-pre.target @1.942s | ||
+ | └─lvm2-monitor.service @1.319s +622ms | ||
+ | └─dm-event.socket @1.317s | ||
+ | └─-.mount | ||
+ | └─system.slice | ||
+ | └─-.slice | ||
+ | </ | ||
Les options de la commande **systemd-analyze** sont : | Les options de la commande **systemd-analyze** sont : | ||
Ligne 1351: | Ligne 1431: | ||
</ | </ | ||
- | ====Consulter les Informations d'une Unité==== | + | ====LAB #4 - Les Cibles |
- | + | ||
- | Le service **sshd** est configuré par le fichier **/ | + | |
- | + | ||
- | < | + | |
- | [root@centos8 ~]# cat / | + | |
- | [Unit] | + | |
- | Description=OpenSSH server daemon | + | |
- | Documentation=man: | + | |
- | After=network.target sshd-keygen.target | + | |
- | Wants=sshd-keygen.target | + | |
- | + | ||
- | [Service] | + | |
- | Type=notify | + | |
- | EnvironmentFile=-/ | + | |
- | EnvironmentFile=-/ | + | |
- | ExecStart=/ | + | |
- | ExecReload=/ | + | |
- | KillMode=process | + | |
- | Restart=on-failure | + | |
- | RestartSec=42s | + | |
- | + | ||
- | [Install] | + | |
- | WantedBy=multi-user.target | + | |
- | </ | + | |
- | + | ||
- | Dans le fichier on peut noter la présence des lignes suivantes dans la section **[Unit]** : | + | |
- | + | ||
- | * **Description=OpenSSH server daemon**, | + | |
- | * Cette directive est utilisée pour donner une courte description des fonctionalités de l' | + | |
- | * **Documentation=man: | + | |
- | * Cette directive stipule les chapitres des manuels et les URLs contenant de l' | + | |
- | * **After=network.target sshd-keygen.target**, | + | |
- | * Cette directive indique les cibles qui devraient être atteients et les Unités qui devraient être démarrées avant l' | + | |
- | * **Wants=sshd-keygen.target**, | + | |
- | * Cette directive stipule une dépendance douce. Autrement dit, Systemd essayera de démarrer l' | + | |
- | + | ||
- | Dans le fichier on peut aussi noter la présence des lignes suivantes dans la section **[Service]** : | + | |
- | + | ||
- | * **Type=notify**, | + | |
- | * Cette directive indique que le service informera Systemd quand son démarrage a terminé, | + | |
- | * **ExecStart=/ | + | |
- | * Cette directive définit l' | + | |
- | * **ExecReload=/ | + | |
- | * Cette directive indique la commande necéssaire pour redémarrer le service, | + | |
- | * **KillMode=process**, | + | |
- | * Cette directive indique comment les processus du service doivent être arrêtés. La valeur de **process** implique l' | + | |
- | * **Restart=on-failure**, | + | |
- | * Cette ligne indique que le service doit être re-démarré en cas d' | + | |
- | * **RestartSec=42s**, | + | |
- | * Cette directive stipule le temps d' | + | |
- | + | ||
- | Dernièrement on note la présence de la ligne suivante dans la section **[Install]** : | + | |
- | + | ||
- | * **WantedBy=multi-user.target**, | + | |
- | * Cette directive indique la Cible dans laquelle le service doit être démarré. La présence de cette directive crée un lien symbolique dans le répertoire **/ | + | |
- | + | ||
- | Pour consulter la liste des dépendances de cette Unité, il convient d' | + | |
- | + | ||
- | < | + | |
- | [root@centos8 ~]# systemctl list-dependencies sshd.service | + | |
- | sshd.service | + | |
- | ● ├─system.slice | + | |
- | ● ├─sshd-keygen.target | + | |
- | ● │ ├─sshd-keygen@ecdsa.service | + | |
- | ● │ ├─sshd-keygen@ed25519.service | + | |
- | ● │ └─sshd-keygen@rsa.service | + | |
- | ● └─sysinit.target | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● | + | |
- | ● │ ├─-.mount | + | |
- | ● │ ├─boot.mount | + | |
- | ● │ └─systemd-remount-fs.service | + | |
- | ● | + | |
- | ● | + | |
- | </ | + | |
- | + | ||
- | L' | + | |
- | + | ||
- | < | + | |
- | [root@centos8 ~]# systemd-analyze critical-chain sshd.service | + | |
- | The time after the unit is active or started is printed after the " | + | |
- | The time the unit takes to start is printed after the " | + | |
- | + | ||
- | sshd.service +56ms | + | |
- | └─network.target @3.799s | + | |
- | └─NetworkManager.service @3.719s +77ms | + | |
- | └─network-pre.target @3.718s | + | |
- | └─firewalld.service @3.004s +713ms | + | |
- | └─polkit.service @2.397s +605ms | + | |
- | └─basic.target @2.392s | + | |
- | └─sockets.target @2.392s | + | |
- | └─sssd-kcm.socket @2.391s | + | |
- | └─sysinit.target @2.379s | + | |
- | └─systemd-update-utmp.service @2.370s +8ms | + | |
- | └─auditd.service @2.317s +52ms | + | |
- | └─systemd-tmpfiles-setup.service @2.118s +196ms | + | |
- | └─import-state.service @2.070s +46ms | + | |
- | └─local-fs.target @2.069s | + | |
- | └─boot.mount @2.006s +62ms | + | |
- | └─systemd-fsck@dev-disk-by\x2duuid-2ae4c035\x2d9244\x2d458c\x2d82c5\x2da49ae169cdb6.service @1.943s +54ms | + | |
- | └─local-fs-pre.target @1.942s | + | |
- | └─lvm2-monitor.service @1.319s +622ms | + | |
- | └─dm-event.socket @1.317s | + | |
- | └─-.mount | + | |
- | └─system.slice | + | |
- | └─-.slice | + | |
- | </ | + | |
- | + | ||
- | ====Les Cibles==== | + | |
Chaque Cible est décrite par un fichier de configuration : | Chaque Cible est décrite par un fichier de configuration : | ||
Ligne 1525: | Ligne 1459: | ||
* **Requires=multi-user.target**, | * **Requires=multi-user.target**, | ||
- | * Cette ligne indique que le **graphical.target** ne peut pas être atteint si le **multi-user.target** n'a pas été atteint | + | * Cette ligne indique que le **graphical.target** ne peut pas être atteint si le **multi-user.target** n'a pas été atteint |
* **After=multi-user.target rescue.service rescue.target display-manager.service**, | * **After=multi-user.target rescue.service rescue.target display-manager.service**, | ||
* Cette ligne indique le **multi-user.target** et **rescue.target** doivent d' | * Cette ligne indique le **multi-user.target** et **rescue.target** doivent d' | ||
Ligne 1533: | Ligne 1467: | ||
* Cette ligne indique quel service doit être démarré. | * Cette ligne indique quel service doit être démarré. | ||
- | ===Contrôler les dépendances d'une Cible=== | + | ===4.1 - Contrôler les dépendances d'une Cible=== |
Les dépendances d'une Cible peuvent être consultées en utilisant la commande **systemctl list-dependencies** : | Les dépendances d'une Cible peuvent être consultées en utilisant la commande **systemctl list-dependencies** : | ||
Ligne 1659: | Ligne 1593: | ||
</ | </ | ||
- | ====La Cible par Défaut==== | + | ===4.2 - La Cible par Défaut=== |
- | ===Consulter la Cible par Défaut=== | + | ==Consulter la Cible par Défaut== |
Pour consulter la cible par défaut, il convient d' | Pour consulter la cible par défaut, il convient d' | ||
Ligne 1677: | Ligne 1611: | ||
</ | </ | ||
- | ===Modifier la Cible par Défaut=== | + | ==Modifier la Cible par Défaut== |
Pour modifier la Cible par défaut avec une prise en compte lors du **prochain** démarrage, il convient d' | Pour modifier la Cible par défaut avec une prise en compte lors du **prochain** démarrage, il convient d' | ||
Ligne 1694: | Ligne 1628: | ||
</ | </ | ||
+ | ==Modifier la Cible en Cours== | ||
+ | Il est possible de modifier la cible actuellement en cours en utilisant la commande **systemctl isolate** : | ||
+ | < | ||
+ | [root@centos8 ~]# systemctl isolate rescue | ||
+ | [root@centos8 ~]# systemctl list-units --type target | egrep " | ||
+ | rescue.target | ||
+ | [root@centos8 ~]# runlevel | ||
+ | 3 1 | ||
+ | [root@centos8 ~]# who -r | ||
+ | | ||
+ | </ | ||
+ | < | ||
+ | [root@centos8 ~]# systemctl isolate multi-user | ||
+ | [root@centos8 ~]# systemctl list-units --type target | egrep " | ||
+ | multi-user.target | ||
+ | [root@centos8 ~]# runlevel | ||
+ | 1 3 | ||
+ | [root@centos8 ~]# who -r | ||
+ | | ||
+ | </ | ||
+ | ====LAB #5 - Gestion des Services==== | ||
- | + | ===5.1 - Gestion des Instances Uniques=== | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | ====Gestion des Services==== | + | |
- | + | ||
- | ===Gestion des Instances Uniques=== | + | |
Commencez par installer le paquet **httpd** : | Commencez par installer le paquet **httpd** : | ||
Ligne 1842: | Ligne 1790: | ||
</ | </ | ||
- | ===Gestion | + | ===5.2 - Gestion |
- | Systemd permet l' | + | Systemd permet l' |
< | < | ||
Ligne 1875: | Ligne 1823: | ||
Une instance créée à partir de ce gabarit devrait avoir un nom sous la forme suivante : | Une instance créée à partir de ce gabarit devrait avoir un nom sous la forme suivante : | ||
- | | + | < |
+ | httpd@< | ||
+ | </ | ||
- | Dans ce fichier on peut constater l' | + | Dans ce fichier on peut constater l' |
- | * %n : est remplacé par le nom complet | + | * %n : est remplacé par le nom complet |
- | * %N : est remplacé par le nom complet non-échapé | + | * %N : est remplacé par le nom complet non-échappé |
- | * %p : est remplacé par le préfixe | + | * %p : est remplacé par le préfixe |
- | * %P : est remplacé par le préfixe non-échapé | + | * %P : est remplacé par le préfixe non-échappé |
- | * %i : est remplacé par le nom de l' | + | * %i : est remplacé par le nom de l' |
- | * %I : est remplacé par le nom de l' | + | * %I : est remplacé par le nom de l' |
- | * %f : est remplacé par le préfixe non-échappé ou le nom de l' | + | * %f : est remplacé par le préfixe non-échappé ou le nom de l' |
* %c : est remplacé par le CGroup de l' | * %c : est remplacé par le CGroup de l' | ||
* %u : est remplacé par le nom de l' | * %u : est remplacé par le nom de l' | ||
* %U : est remplacé par l'UID de l' | * %U : est remplacé par l'UID de l' | ||
* %H : est remplacé par le nom d' | * %H : est remplacé par le nom d' | ||
- | * %% : est remplac" par le caractère **%**. | + | * %% : est remplacé" par le caractère **%**. |
Créez maintenant deux copies du fichier **/ | Créez maintenant deux copies du fichier **/ | ||
Ligne 1908: | Ligne 1858: | ||
Editez la directive **Listen** du fichier **/ | Editez la directive **Listen** du fichier **/ | ||
+ | < | ||
[root@centos8 ~]# vi / | [root@centos8 ~]# vi / | ||
[root@centos8 ~]# more / | [root@centos8 ~]# more / | ||
Ligne 2085: | Ligne 2036: | ||
</ | </ | ||
+ | ===5.3 - Interdire la Modification du Statut d'un Service=== | ||
+ | Il est possible d' | ||
+ | < | ||
+ | [root@centos8 ~]# systemctl status httpd.service | ||
+ | ● httpd.service - The Apache HTTP Server | ||
+ | | ||
+ | | ||
+ | Docs: man: | ||
+ | Jun 07 18:27:25 centos8.ittraining.loc httpd[58535]: | ||
+ | Jun 07 18:27:29 centos8.ittraining.loc systemd[1]: Stopping The Apache HTTP Server... | ||
+ | Jun 07 18:27:30 centos8.ittraining.loc systemd[1]: httpd.service: | ||
+ | Jun 07 18:27:30 centos8.ittraining.loc systemd[1]: Stopped The Apache HTTP Server. | ||
+ | Jun 07 18:27:32 centos8.ittraining.loc systemd[1]: Starting The Apache HTTP Server... | ||
+ | Jun 07 18:27:32 centos8.ittraining.loc systemd[1]: Started The Apache HTTP Server. | ||
+ | Jun 07 18:27:32 centos8.ittraining.loc httpd[58760]: | ||
+ | Jun 07 18:27:34 centos8.ittraining.loc systemd[1]: Stopping The Apache HTTP Server... | ||
+ | Jun 07 18:27:36 centos8.ittraining.loc systemd[1]: httpd.service: | ||
+ | Jun 07 18:27:36 centos8.ittraining.loc systemd[1]: Stopped The Apache HTTP Server. | ||
+ | |||
+ | [root@centos8 ~]# systemctl mask httpd.service | ||
+ | Created symlink / | ||
+ | |||
+ | [root@centos8 ~]# systemctl enable httpd.service | ||
+ | Failed to enable unit: Unit file / | ||
+ | |||
+ | [root@centos8 ~]# systemctl start httpd.service | ||
+ | Failed to start httpd.service: | ||
+ | </ | ||
+ | |||
+ | Pour autoriser de nouveau les modifications, | ||
+ | |||
+ | < | ||
+ | [root@centos8 ~]# systemctl unmask httpd.service | ||
+ | Removed / | ||
+ | |||
+ | [root@centos8 ~]# systemctl enable httpd.service | ||
+ | Created symlink / | ||
+ | |||
+ | [root@centos8 ~]# systemctl start httpd.service | ||
+ | |||
+ | [root@centos8 ~]# systemctl status httpd.service | ||
+ | ● httpd.service - The Apache HTTP Server | ||
+ | | ||
+ | | ||
+ | Docs: man: | ||
+ | Main PID: 59101 (httpd) | ||
+ | | ||
+ | Tasks: 213 (limit: 23719) | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | Jun 07 18:30:59 centos8.ittraining.loc systemd[1]: Starting The Apache HTTP Server... | ||
+ | Jun 07 18:30:59 centos8.ittraining.loc systemd[1]: Started The Apache HTTP Server. | ||
+ | Jun 07 18:31:00 centos8.ittraining.loc httpd[59101]: | ||
+ | </ | ||
=====Arrêt du Système===== | =====Arrêt du Système===== | ||
+ | |||
+ | Sous RHEL / CentOS 8 les commandes **halt**, **poweroff**, | ||
+ | |||
+ | < | ||
+ | [root@centos8 ~]# ls -l / | ||
+ | lrwxrwxrwx. 1 root root 16 Apr 7 16:55 / | ||
+ | lrwxrwxrwx. 1 root root 16 Apr 7 16:55 / | ||
+ | lrwxrwxrwx. 1 root root 16 Apr 7 16:55 / | ||
+ | lrwxrwxrwx. 1 root root 16 Apr 7 16:55 / | ||
+ | </ | ||
+ | |||
+ | La manière recommendée d' | ||
+ | |||
+ | * systemctl halt | ||
+ | * systemctl poweroff | ||
+ | * systemctl reboot | ||
+ | * systemctl shutdown | ||
+ | |||
+ | Il est cependant toujours possibles d' | ||
====La Commande shutdown==== | ====La Commande shutdown==== | ||
Ligne 2102: | Ligne 2132: | ||
La commande utilisée pour arrêter le système est la commande **shutdown** : | La commande utilisée pour arrêter le système est la commande **shutdown** : | ||
- | shutdown [-t sec] [-akrhHPfnc] heure [message] | + | shutdown [-t sec] [-HPrhkc] heure [message] |
===Options de la commande=== | ===Options de la commande=== | ||
Ligne 2109: | Ligne 2139: | ||
< | < | ||
- | Usage: | + | [root@centos8 ~]# shutdown --help |
- | -a: use /etc/shutdown.allow | + | shutdown |
- | | + | |
- | | + | |
- | | + | |
- | -P: halt action is to turn off power. | + | |
- | -H: halt action is to just halt. | + | |
- | -f: do a ' | + | |
- | -F: Force fsck on reboot. | + | |
- | -n: do not go through " | + | |
- | -c: cancel a running shutdown. | + | |
- | -t secs: delay between warning and kill signal. | + | |
- | ** the " | + | |
- | </ | + | |
- | Parmi les options les plus importantes, | + | Shut down the system. |
- | ^ Option ^ Description ^ | + | |
- | | -h | Arrêter le système | | + | -H --halt |
- | | -r | Re-démarrer le système | | + | -P --poweroff |
- | | -c | Annuler l'opération shutdown en cours | | + | |
- | | -f | Re-démarrer rapidement sans vérifier les systèmes de fichiers | | + | -h |
- | | -F | Forcer la vérification des systèmes de fichiers lors du prochain démarrage | | + | -k Don't halt/ |
+ | | ||
+ | -c | ||
+ | </ | ||
L' | L' | ||
Ligne 2137: | Ligne 2158: | ||
^ Valeur ^ Description ^ | ^ Valeur ^ Description ^ | ||
| hh:mm | L' | | hh:mm | L' | ||
- | | +m | Nombre de minutes avant que l' | + | | +m | Nombre de minutes avant que l' |
- | | now | L' | + | | now | L' |
<WRAP center round important 60%> | <WRAP center round important 60%> | ||
- | **Important** : Si l' | + | **Important** : Si l' |
</ | </ | ||
- | Dans votre VM, ouvrez deux terminaux. Dans le premier passez en tant que root. Planifiez ensuite | + | L' |
< | < | ||
- | [root@centos7 | + | [root@centos8 |
- | + | Mon Jun 7 18:58:26 EDT 2021 | |
- | Broadcast message from trainee@centos.fenestros.loc | + | Shutdown scheduled |
- | (/ | + | |
- | + | ||
- | The system is going down for reboot in 30 minutes! | + | |
- | </ | + | |
- | + | ||
- | Dans le deuxième terminal est passez en tant que route. Annulez ensuite le shutdown : | + | |
- | + | ||
- | < | + | |
- | [trainee@centos7 ~]$ su - | + | |
- | Mot de passe : | + | |
- | [root@centos7 ~]# shutdown -c | + | |
- | </ | + | |
- | + | ||
- | Retournez au premier terminal et constatez le message affiché : | + | |
- | + | ||
- | < | + | |
- | [root@centos7 ~]# shutdown -r +30 | + | |
- | + | ||
- | Broadcast message from trainee@centos.fenestros.loc | + | |
- | (/ | + | |
- | + | ||
- | The system is going down for reboot in 30 minutes! | + | |
- | + | ||
- | + | ||
- | shutdown: Shutdown cancelled | + | |
- | [root@centos7 ~]# | + | |
</ | </ | ||
==== La Commande reboot==== | ==== La Commande reboot==== | ||
- | Cette commande redémarre le système. Quand le système fonctionne normalement, | + | Cette commande redémarre le système. |
===Options de la commande=== | ===Options de la commande=== | ||
Ligne 2187: | Ligne 2182: | ||
< | < | ||
- | [root@centos7 | + | [root@centos8 |
- | Usage: | + | reboot [OPTIONS...] [ARG] |
Reboot the system. | Reboot the system. | ||
- | Options: | + | |
- | -n, --no-sync | + | |
- | -f, --force | + | -p --poweroff |
- | | + | --reboot |
- | -w, --wtmp-only | + | -f --force |
- | | + | -w --wtmp-only |
- | -q, --quiet | + | -d --no-wtmp |
- | | + | |
- | --help display this help and exit | + | |
- | | + | |
- | + | ||
- | This command is intended to instruct the kernel to reboot or halt the system; | + | |
- | when run without the -f option, or when in a system runlevel other than 0 or 6, | + | |
- | it will actually execute | + | |
- | + | ||
- | + | ||
- | Report bugs to < | + | |
</ | </ | ||
==== La Commande halt==== | ==== La Commande halt==== | ||
- | Cette commande arrête le système. Quand le système fonctionne normalement, | + | Cette commande arrête le système. |
===Options de la commande=== | ===Options de la commande=== | ||
Ligne 2219: | Ligne 2206: | ||
< | < | ||
- | [root@centos7 | + | [root@centos8 |
- | Usage: | + | halt [OPTIONS...] |
Halt the system. | Halt the system. | ||
- | Options: | + | |
- | -n, --no-sync | + | |
- | -f, --force | + | -p --poweroff |
- | | + | --reboot |
- | -w, --wtmp-only | + | -f --force |
- | | + | -w --wtmp-only |
- | -q, --quiet | + | -d --no-wtmp |
- | | + | |
- | --help display this help and exit | + | |
- | | + | |
- | + | ||
- | This command is intended to instruct the kernel to reboot or halt the system; | + | |
- | when run without the -f option, or when in a system runlevel other than 0 or 6, | + | |
- | it will actually execute | + | |
- | + | ||
- | + | ||
- | Report bugs to < | + | |
</ | </ | ||
==== La Commande poweroff==== | ==== La Commande poweroff==== | ||
- | Cette commande arrête le système et coupe l' | + | Cette commande arrête le système et coupe l' |
===Options de la commande=== | ===Options de la commande=== | ||
Ligne 2251: | Ligne 2230: | ||
< | < | ||
- | [root@centos7 | + | [root@centos8 |
- | Usage: | + | poweroff [OPTIONS...] |
Power off the system. | Power off the system. | ||
- | Options: | + | |
- | -n, --no-sync | + | |
- | -f, --force | + | -p --poweroff |
- | | + | --reboot |
- | -w, --wtmp-only | + | -f --force |
- | | + | -w --wtmp-only |
- | -q, --quiet | + | -d --no-wtmp |
- | | + | |
- | --help display this help and exit | + | |
- | | + | |
- | + | ||
- | This command is intended to instruct the kernel to reboot or halt the system; | + | |
- | when run without the -f option, or when in a system runlevel other than 0 or 6, | + | |
- | it will actually execute | + | |
- | + | ||
- | + | ||
- | Report bugs to < | + | |
</ | </ | ||
----- | ----- | ||
- | < | + | Copyright © 2024 Hugh Norris. |
- | <div align=" | + | |
- | Copyright © 2021 Hugh Norris. | + | |
- | </ | + |