-- Users insertion
INSERT INTO "user" (id, pseudo, email, password, photo_id) VALUES
('2939a60c-3f62-4f6e-8e01-32566e0682c6', 'Administrator', 'admin@admin.adm', '$2a$10$0StXSF/n9fbLM8onEmzjAOUdUqX1uIo5u.IdE22C5NlB1ue5KzYaa', NULL),
('51393fd2-999a-42b9-819f-485cd6763bcd', 'Sweety', 'ac.gabutdeloraine@gmail.com', '$2a$10$YsJGJQueGik/HGEaDq8ik.0ldRyTRpLG0.OaTEGi6lDEAsH.oJAtq', NULL),
('2073a7eb-b3e5-4b33-855d-067c8350eddb', 'Cross', 'onizuka.cross@gmail.com', '$2a$10$6gWkzaFPH9n6qVGap2S0X.46AdR79a72Y4GYvhPE1OkA.nEGehswG', NULL),
('6151c195-538e-42bb-8ac9-4417aec2a7ae', 'test', 'test@test.ter', '$2a$10$nsdqv33FxLldBr2bQ31WJOHctEEuksT9Mcow5qmP.5m6Jz7OwUOEa', NULL),
('6f1d6adb-ba9b-49d6-b5d2-7c57094db7a9', 'test', 'test@test.terr', '$2a$10$5U0Eh9HckADBXIiQ894B1utsPFuo852ZlFVRktuzNFT3iZuVEYCZK', NULL),
('d1d557a6-88b1-4274-994e-f9a9a6097997', 'Takiguchi', 'florian.thierry72@gmail.com', '$2a$10$sa4WNtDR.oXb6NH7pS8v5.JeIg0TqU2ZoDjvwnPNE2qvhb4L2KAsu', NULL),
('4013ecaf-4a1e-485e-91c6-1892885c606d', 'Kage', 'darknesseagle26@hotmail.fr', '$2a$10$yLhPl1CfGh6XFbllj.s65OmioMBumfJsU6wVJw4hxCYmoL2irjvW2', NULL);

INSERT INTO user_role (user_id, role) VALUES
('2939a60c-3f62-4f6e-8e01-32566e0682c6', 0),
('2939a60c-3f62-4f6e-8e01-32566e0682c6', 1),
('51393fd2-999a-42b9-819f-485cd6763bcd', 0),
('2073a7eb-b3e5-4b33-855d-067c8350eddb', 0),
('6151c195-538e-42bb-8ac9-4417aec2a7ae', 0),
('6f1d6adb-ba9b-49d6-b5d2-7c57094db7a9', 0),
('d1d557a6-88b1-4274-994e-f9a9a6097997', 0),
('4013ecaf-4a1e-485e-91c6-1892885c606d', 0);

-- Pictures insertion
INSERT INTO picture (id, publisher_id) VALUES
('19bcb3b2-199a-4c68-9257-e33a81985ef5', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('d2a743e4-c54f-4e6d-bd1b-69a62729d8eb', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('446a65ff-2f00-4705-875d-28df1f656204', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('f80e0938-8857-4214-bbaf-8a277b91a772', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('d66f4db9-f21c-4b47-b007-48ebae484b27', '4013ecaf-4a1e-485e-91c6-1892885c606d'),
('a01ff6f9-f366-4720-b3c8-c59ff3d31675', '4013ecaf-4a1e-485e-91c6-1892885c606d'),
('4e5f8d00-c66e-4dc9-bf80-b7c1c4d6ea94', '4013ecaf-4a1e-485e-91c6-1892885c606d'),
('b541c414-8646-45a6-ab60-c3ab48ef5e93', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('9a28d33f-37af-45aa-8be6-88f41dcd14f6', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('7d0d4580-95b6-4369-bfce-7d57f7288d01', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('1759c754-768b-4773-b9fc-e3944af76f8e', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('8971958f-b494-4529-8ad9-0170ad3213c8', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('4c9dbcba-15a9-4e64-b186-8b266c0c00cb', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('8b07b416-d363-4564-8587-80ba40c911fb', '4013ecaf-4a1e-485e-91c6-1892885c606d'),
('ddf62d9a-af98-4715-b8ab-10c57d306d85', '4013ecaf-4a1e-485e-91c6-1892885c606d'),
('b4ffa7df-d39e-4970-8fd0-0a27844d8af6', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('b687928c-4b96-454e-be25-8615e6fc5ca5', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('69bf1b33-9cc3-4e97-a27d-2236bb2c2a7f', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('a6f97612-b754-4291-8882-07f37d17bc91', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('2ce8a032-5e4d-4921-a589-ee51b3c58437', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('ae3d80a1-5608-4062-bf20-bfed1bf558dc', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('c3d35742-f030-4e5f-b057-d8c9e2b0c5e0', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('70957e29-699a-4a27-a70d-d1fc40f51c9d', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('07ff7209-efd5-482a-a7e4-0cbf6c36af68', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('f0669a6a-f772-49a5-a649-6e0747e88e29', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('2d45d296-d63c-487c-a435-7f4f9a5d6a57', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('c6941027-8c1b-47cd-9640-a602b1d99d15', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('feadaf61-22a1-4722-baf1-b8e26dda7075', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('f0bab31c-092c-4013-aa73-693d50a0098d', 'd1d557a6-88b1-4274-994e-f9a9a6097997'),
('fdc92c27-cfad-4e77-9502-a265fed026e2', '2939a60c-3f62-4f6e-8e01-32566e0682c6');

-- Categories insertion
INSERT INTO category (id, name, parent_category_id) VALUES
('3dec7c5a-e7d6-4b21-beb1-209cdf5be067', 'Développement', NULL),
('57e3ddce-e7d2-446e-a3c0-667f1a433d3c', 'Administration système', NULL),
('04347de5-2814-4aff-9fe9-51b34c1c743e', 'Administration réseau', NULL),
('41b2792e-6f65-48be-8718-82ac58101aa8', 'Divers', NULL),
('61f9fbf3-3340-4ea4-9661-04089377bb2e', 'Java', NULL),
('753570cc-3403-4bac-b9da-6c19875d98b7', 'C++', NULL),
('1515ff79-e42e-4d84-9496-6cdcf1cb74f2', 'Android', NULL),
('b58bda0b-2f45-4c7a-8ece-1a206fb32a7a', 'Sql', NULL),
('0f4c4d7c-2ccc-4725-88b6-672aa518da90', 'Linux', NULL),
('7234cd9e-3834-45c5-973b-1574f5c3c4c6', 'Autre', NULL),
('49b4df8a-19f5-459b-b508-6b7c71332523', 'TypeScript', NULL),
('2cad9c28-ab5d-4c8f-b7da-70ff8bc02586', 'Windows', NULL),
('f46fb104-4f53-4732-b33b-6a3ef8c2c0a3', 'Outillage', NULL);

-- Publications insertion
INSERT INTO publication (id, key, title, text, description, creation_date, illustration_id, author_id, category_id) VALUES
('907385da-644d-43e8-acc2-7a4a49bf6237', 'POSTPN24WIYDQY', 'Https et wildly', '
[h1]Introduction[/h1]
Depuis la version 8 de wildfly, la mise en place du protocole https se fait via la section "Undertow" de la configuration "standalone.xml" de wildfly.


[h1]Certificat CA CERT[/h1]
[h2]Génération d''un certificat CA CERT[/h2]
Depuis un terminal Linux, taper les commandes suivantes :

[code lg="bash"]
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX
[/code]

La clef privée sera générée dans le fichier "key.pem" et le certificat dans le fichier "cert.pem".

Ensuite, il faut convertir le certificat dans le bon format.
Pour cela, taper la commande suivante dans un terminal :

[code lg="bash"]
openssl pkcs12 -export -inkey key.pem -in cert.pem -out key.p12
[/code]

[h2]Installation du certificat[/h2]
Il suffit de copier le fichier "key.p12" dans un répertoire de wildfly, comme "configuration" par exemple :

[code lg="bash"]
sudo cp key.p12 /opt/wildfly/standalone/configuration/key.p12
[/code]


[h1]Configuration de Wildfly[/h1]
[h2]Déclaration du certificat[/h2]
Il faut ouvrir le fichier "$WILDFLY_HOME/standalone/configuration/standalone.xml" et y insérer les balises ci-dessous dans le nœud "/server/management/" du fichier :

[code lg="markup"]
<security-realm name="SslRealm">
    <server-identities>
        <ssl>
            <keystore path="/opt/wildfly/standalone/configuration/key.p12" keystore[REDACTED]" provider="PKCS12" />
        </ssl>
    </server-identities>
</security-realm>
[/code]

[h2]Activation du protocole "https"[/h2]
Toujours dans le fichier "$WILDFLY_HOME/standalone/configuration/standalone.xml", il faut remplacer le nœud "subsystem undertow" dans le nœud "/server/profile/" du fichier par les balises suivantes :

[code lg="markup"]
<subsystem xmlns="urn:jboss:domain:undertow:3.0">
    <buffer-cache name="default" />
    <server name="default-server">
        <http-listener name="default" socket-binding="http"
            redirect-socket="https" />
        <https-listener name="default-ssl" socket-binding="https"
            security-realm="SslRealm" />
        <host name="default-host" alias="localhost">
            <location name="/" handler="welcome-content" />
            <filter-ref name="server-header" />
            <filter-ref name="x-powered-by-header" />
        </host>
    </server>
    <servlet-container name="default">
        <jsp-config />
        <websockets />
    </servlet-container>
    <handlers>
        <file name="welcome-content" path="${jboss.home.dir}/welcome-content" />
    </handlers>
    <filters>
        <response-header name="server-header" header-name="Server"
            header-value="WildFly/10" />
        <response-header name="x-powered-by-header"
            header-name="X-Powered-By" header-value="Undertow/1" />
    </filters>
</subsystem>
[/code]

Seules les balises "<http-listener ... />" et "<https-listener ... />" sont (normalement) impactées.
Note : L''attribut "security-realm" du nœud "https-listener" doit correspondre au nom du security-realm définit dans la section précédente.', 'Mise en place du protocole https dans Wildfly 10.', '2017-10-03 23:08:59 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '61f9fbf3-3340-4ea4-9661-04089377bb2e'),
('426097b1-804e-458d-9a95-3c3715c019d4', 'POSTKNSF2TAG46', 'Configuration du touchpad sous Linux', '
[h1]Le fichier de configuraiton[/h1]
Le fichier de configuration est le suivant :
[code lg="bash"]
/usr/share/X11/xorg.conf.d/50-synaptics.conf
[/code]

[h1]Configuration[/h1]
Il faut y écrire la configuration suivante afin d''activer les options ce-dessous :
- Fonctionnement normal du touchpad
- Taping à un doigt (clic gauche)
- Taping à deux doigts (clic droit)
- Taping à trois doigts (clic central)
- Scrolling vertical et horizontal à deux doigts
[code lg="bash"]
Section "InputClass"
	Identifier "Touchpad"		# Required
	MatchIsTouchpad "yes"		# Required
	Driver "synaptics"		# Required
	Option "TapButton1" "1"		# Taping 1 finger (left clic)
	Option "TapButton2" "3"		# Taping 2 fingers (right clic)
	Option "TapButton3" "2"		# Taping 3 fingers (middle clic)
	Option "VertTwoFingerScroll" "1"	# Vertical scrolling  (2 fingers)
	Option "HorizTwoFingerScroll" "1"	# Horizontal scrolling (2 fingers)
	Option "VertEdgeScroll" "1"
EndSection
[/code]

', 'Gestion du touchpad, permettant d''activer le tapping, le mode two fingers, three fingers, le scrolling etc...', '2017-10-04 10:58:17 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('dceadd24-fa8d-4fc7-9262-d5178b04f3cb', 'POST8P2DCSTYA7', 'Installation d''un serveur git', '[h1]Préambule[/h1]
Il est possible de s''abstraire des plateformes GitHub, GitLab ou encore GitBlit pour mettre en place un serveur git pour son équipe, et gratuitement.
Le logiciel git fournit des fonctionnalités natives permettant d''installer un dépôt git côté serveur, qui sera mutualisé entre tous les acteurs du projet.

[h1]Dépendances[/h1]
Pour installer un serveur git il suffit juste d''installer git sur son serveur :
[code lg="bash"]
sudo apt-get install git
[/code]

[h1]Installation[/h1]
Par convention, les répertoires correspondant à un dépôt git côté serveur sont suffixés par ".git".
Exemple :
[code lg="bash"]
sudo mkdir /opt/git/my_repository.git
[/code]

Il faut ensuite initialiser le dépôt via la commande suivante :
[code lg="bash"]
git init --bare
[/code]

', 'Mise en place d''un serveur git sur un serveur Linux.', '2017-10-04 14:38:32 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('1a09e784-1792-4bc5-9d0e-9d19f2cd6da8', 'POSTK1LNP0F5JT', 'Supprimer un utilisateur dans Wildfly', '[h1]Désactivation d''un utilisateur[/h1]
Il faut utiliser le script "add-user.sh" présent dans le répertoire "bin/" du dossier de wildfly.
[code lg="bash"]
sh $WILDFLY_HOME/bin/add-user.sh -d
[/code]

[h1]Suppression d''un utilisateur[/h1]
Il faut supprimer l''entrée correspondant à l''utilisateur dans le fichier "mgmt-users.properties" situé dans le répertoire "standalone/configuration/" du dossier de wildfly.
[code lg="bash"]
vim $WILDFLY_HOME/standalone/configuration/mgmt-users.properties
[/code]

[h3]Sources[/h3]
https://it.i88.ca/2014/10/how-to-disable-delete-user-in-wildfly.html', 'Procédure permettant de désactiver ou de supprimer un utilisateur sur le serveur Wildfly.', '2017-10-05 09:48:18 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '61f9fbf3-3340-4ea4-9661-04089377bb2e'),
('73290d21-7ecc-4d37-99df-2643189705ef', 'POSTT84X5OJ17B', 'Memento GPG', '[h1]Installation[/h1]
[code lg="bash"]
sudo apt-get install gnupg
[/code]

[h1]Créer une paire de clefs[/h1]
[code lg="bash"]
gpg --gen-key
[/code]

[h1]Lister les clefs du trousseau[/h1]
[h2]Clefs publiques[/h2]
[code lg="bash"]
gpg --list-keys
[/code]

[h2]Clefs privées[/h2]
[code lg="bash"]
gpg --list-secret-keys
[/code]

[h1]Chiffrer un fichier[/h1]
[code lg="bash"]
gpg --output output-file.gpg --encrypt --recipient destinataire@email.org input-file
[/code]

[h1]Déchiffrer un fichier[/h1]
[h2]Dans un fichier[/h2]
La commande suivante permet de déchiffrer un fichier chiffré, et d''enregistrer le résultat dans un fichier de sortie :
[code lg="bash"]
gpg --output output-file --decrypt input-file.gpg
[/code]

[h2]Dans la console[/h2]
La commande suivante permet de déchiffrer un fichier chiffré et affiche le résultat uniquement dans la console active :
[code lg="bash"]
gpg --decrypt doc.gpg
[/code]

[h3]Sources[/h3]
https://www.gnupg.org/gph/en/manual/x110.html
https://help.github.com/articles/generating-a-new-gpg-key/', 'Récapitulatif des commandes de base de l''outil GPG, comme la création d''une paire de clefs, lister les clefs du trousseau, chiffrer un fichier, déchiffrer un fichier etc...', '2017-10-05 10:01:05 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('726c3b14-51c8-4791-a3ad-9b765277935c', 'POSTD6WFCMVNBB', 'Problème de montage ntfs', '[h1]Problème[/h1]
Vous rencontrez le message d''erreur suivant lors du montage d''une partifion "ntfs" :
[code lg="bash"]
Error mounting /dev/sdXY at /path/mounting/.../
Metadata kept in Windows cache, refused to mount.
Failed to mount ''/dev/sdaXY'': Operation not permitted
The NTFS partition is in an unsafe state. Please resume and shutdown
Windows fully (no hibernation or fast restarting), or mount the volume
read-only with the ''ro'' mount option
[/code]

[h1]Résolution[/h1]
Il vous suffit de taper la commande suivante :
[code lg="bash"]
sudo ntfsfix /dev/sdXY
[/code]

(En adaptant les numéros de partition, bien évidemment)', 'Corriger une erreur de montage d''une partition ntfs sous Linux.', '2017-11-23 23:22:53 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('e923d2f5-a3de-4617-b180-5f01837932ff', 'POSTTT7DVJMAI2', 'Progression avec la commande dd', '[h1]Problème[/h1]
Lors de l''utilisation de la commande "dd", le terminal n''affiche aucune information jusqu''à ce que la commande ait terminé son travail.
[h1]Solution[/h1]
Il faut utiliser la commande "pv" comme dans l''exemple suivant :
[code lg="bash"]
sudo dd bs=1M if=/path/to/iso/file | pv -s 4G | sudo dd of=/dev/sdb
[/code]

L''argument "4G" étant la taille de l''iso désigné par l''argument "if".', 'Suivre la progression de la commande dd avec la commande pv.', '2018-03-10 13:51:23 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('3453207d-33e0-47e8-af56-88a466e5d800', 'POSTSBLKUTN222', 'Montage permanent d''un disque NTFS sous GNU Linux', '[h1]Détection de la partition[/h1]
Il faut récupérer l''identifiant de la partition avec la commande suivante :
[code lg="bash"]
sudo blkid
[/code]

Voici un exemple de résultat :
[code lg="bash"]
/dev/sda1: LABEL="Debian" UUID="nm1YR10T-JK8f-ljs5-fnm1-irinkwnF0e38" TYPE="ext4" PARTUUID="nT5bB2Ug-01"
/dev/sdb1: LABEL="NTFSPartition" UUID="6TTHX73QUJB3OTUR" TYPE="ntfs" PARTUUID="hA805qHA-02"
[/code]

Nous avons besoin de l''UUID de la partition "NTFSPartition", soit : 6TTHX73QUJB3OTUR.
[h1]Configuration du système[/h1]
Il faut éditer le fichier "/etc/fstab" :
[code lg="bash"]
sudo vim /etc/fstab
[/code]

Et ajouter la ligne suivante :
[code lg="bash"]
UUID=6TTHX73QUJB3OTUR /media/data ntfs defaults,errors=remount-ro 0 1
[/code]

Description de la ligne :
- UUID = id du disque fourni par la commande blkid
- /media/data = emplacement de montage, c’est-à-dire le chemin à partir duquel le disque sera accessible
- ntfs = type de disque fourni par la commande blkid
- defaults,errors=remount-ro = paramètre de la commande mount pour monter le disque, reportez-vous au manuel (commande man mount) pour voir ce qu’il est possible d’utiliser.
- 0 = aucune idée de ce à quoi sert ce paramètre dump
- 1 = aucune idée de ce à quoi sert ce paramètre pass
[h1]Test[/h1]
Pour tester le résultat sans redémarrer (c’est plus prudent, on ne sait jamais), vous pouvez recharger la table de montage à chaud par la commande suivante :
[code lg="bash"]
sudo mount -a
[/code]

', 'Configuration à effectuer pour monter un disque ou une partition en NTFS sous GNU Linux.', '2017-10-08 15:53:19 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('11576b50-fdac-4ae0-bdf2-d92b82e5d949', 'POSTS0952DGOHX', 'Uploader une image en ajax', '[h1]Introduction[/h1]
La problématique est d''envoyer un fichier via jQuery en mode AJAX au serveur.
Il est en théorie impossible d''envoyer un fichier depuis JavaScript car lire un fichier depuis le disque dur du client avec JS constituerait une faille de sécurité.
Cependant, il est possible d''envoyer un fichier via un "input" de type "file".
La démarche à suivre est détaillée par la suite.
[h1]Code[/h1]
[h2]Côté html[/h2]
Pour la partie html, on a juste besoin d''un input de type file :

[code lg="markup"]
<input type="file" id="myFile" />
[/code]

[h2]Côté JavaScript[/h2]
Du côté JS, on va définir l''envoi du fichier pour l''évènement "onchange" de l''input, afin que le fichier soit uploadé directement après que l''utilisateur ait choisi un fichier :

[code lg="javascript"]
$(''#myFile'').on(''change'', (event) => {
	    // On stoppe les évènements habituels
	    event.stopPropagation();
	    event.preventDefault();

	    // Récupération du fichier sélectionné
	    let files = event.target.files;
	    let data = new FormData();
	    $.each(files, (key, value) => {
	        data.append(key, value);
	    });

	    // Envoi du fichier au serveur
	    $.ajax({
	        url: ''./UploadFileRoute'',
	        type: ''POST'',
	        data: data,
	        cache: false,
	        processData: false,
	        contentType: false,
	        success: function(data, textStatus, jqXHR) {
	        	// Actions à réaliser une fois l''envoi réussi
	        }, error: function(jqXHR, textStatus, errorThrown) {
	        	// Actions à réaliser si l''envoi échoue
	        }
	    });
});
[/code]

[h2]Côté Java[/h2]
Du côté du serveur, il s''agit d''une récupération classique d''un fichier via une servlet :

[code lg="java"]
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			request.getParts().stream().forEach(part -> saveUploadedFile(part));
		} catch (IOException | ServletException pEx) {
			System.err.println("Error during picture file receiving.");
			pEx.printStackTrace();
		} catch(Exception pEx) {
			pEx.printStackTrace();
		}

		response.getWriter().write("File received!");
	}
[/code]

Et voilà.', 'Envoi d''une image avec Ajax, JSP et Servlets.', '2017-11-01 09:24:05 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '61f9fbf3-3340-4ea4-9661-04089377bb2e'),
('c2537adc-4f1f-4a19-806e-1680bb074bad', 'POSTJ3BWNWIOUL', 'Lister les colonnes d''une table PostgreSQL.', '[h1]Requête[/h1]
Depuis un terminal, se connecter à l''outil ''psql'' puis exécuter la requête suivante :
[code lg="sql"]
SELECT column_name FROM information_schema.columns WHERE table_name = ''tablename'';
[/code]

', 'Lister les colonnes d''une table PostgreSQL.', '2017-11-10 15:10:56 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'b58bda0b-2f45-4c7a-8ece-1a206fb32a7a'),
('3ee0accb-b7b5-4755-ae40-d6eed6f19384', 'POSTBSGAW8A0SW', 'Gnome-shell, configurer un navigateur', '[h1]Le besoin[/h1]
Définir un navigateur alternatif comme celui par défaut sur Gnome-shell.

[h1]Réalisation[/h1]
[h2]Le raccourci[/h2]
Pour ce faire, il faut créer un fichier "*.desktop" dans son répertoire personnel à cet emplacement :
[code lg="bash"]
/home/user/.local/share/applications/
[/code]

Voici un exemple du contenu du fichier "firefox-quantum.desktop", pour lancer Firefox Quantum, installé dans "/opt" :
[code lg="bash"]
[Desktop Entry]
Comment=Firefox browser
Terminal=false
Name=Firefox Quantum
Exec=/opt/firefox/firefox %u
Type=Application
Icon=/opt/firefox/browser/icons/mozicon128.png
[/code]

Note : Il est important de mettre le "%u" à la fin de la commande sans quoi, l''ouverture des liens depuis une autre application n''ouvrira pas le navigateur sur la page du lien.
[h2]Configuration[/h2]
[h3]Graphique[/h3]
Cliquer sur le menu tout en haut à droite de l''écran afin d''ouvrir la pop-up de configuration rapide.
Cliquer sur le bouton tout en bas à gauche afin d''ouvrir les paramètres système.
Cliquer sur le bouton "Détails", puis sur l''onglet "Applications par défaut".
À partir de maintenant, il faut sélectionner le navigateur désiré dans la liste déroulante "Sites Web".

Si le navigateur voulu n''apparaît pas dans la liste, il faudra procéder via la ligne de commande.
[h3]Ligne de commande[/h3]
Se placer dans le répertoire "/home/user/.local/share/applications/", puis taper les commandes suivantes :
[code lg="bash"]
gvfs-mime --set x-scheme-handler/http firefox-quantum.desktop
gvfs-mime --set x-scheme-handler/https firefox-quantum.desktop
[/code]

On peut vérifier la configuration avec la commande suivante :
[code lg="bash"]
xdg-mime query default text/html && xdg-mime query default x-scheme-handler/http && xdg-mime query default x-scheme-handler/https &&  xdg-mime query default x-scheme-handler/about
[/code]

', 'Définir un navigateur par défaut sur Gnome-shell', '2017-11-15 21:10:28 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('19f4eea7-8cbe-4679-9997-89ddd156889a', 'POSTWC1BQG8VYN', 'Ouvrir PostgreSQL au monde extérieur', '[h1]Problème[/h1]
Depuis une machine tierce, vous n''arrivez pas à vous connecter à votre serveur PostgreSQL.
Depuis PgAdmin3, par exemple, vous obtenez le message d''erreur suivant :
[code lg="bash"]
Error connecting to the server: n''a pas pu se connecter au serveur : Connexion refusée
Le serveur est-il actif sur l''hôte « 192.168.0.XX » et accepte-t-il les connexions
TCP/IP sur le port 5432 ?
[/code]

[h1]Contexte[/h1]
L''installation par défaut de PostgreSQL n''autorise que les connexions locales.
[h1]Solution[/h1]
Il suffit de modifier le fichier "postgresql.conf" et "pg_hba.conf".
[h2]postgresql.conf[/h2]
Dans le fichier "postgresql.conf", il faut modifier ou ajouter la signe suivante, afin que PostgreSQL écoute sur toutes les interfaces réseau :
[code lg="bash"]
listen_addresses = ''*''
[/code]

[h2]pg_hba.conf[/h2]
Il faut y ajouter la page d''adresses IP depuis laquelle PostgreSQL accepte les connexions :
[code lg="bash"]
host    all    all    192.168.1.0/24    md5
[/code]

', 'Configurer PostgreSQL afin de pouvoir s''y connecter depuis une autre machine.', '2017-11-17 22:09:12 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'b58bda0b-2f45-4c7a-8ece-1a206fb32a7a'),
('646a0606-289f-4e25-8b37-fab159c8c6e3', 'POSTZTYIGAA9BR', 'Import SQL depuis un fichier', '[h1]Commande[/h1]
Depuis un terminal, entrer la commande suivante :
[code lg="bash"]
   psql "dbname=''dbName'' user=''userName'' password=''userPassword'' host=''dbHost''" -f sqlFile.sql
[/code]

Plus simplement, si on est connecté sur le serveur postgresql, on peut omettre certains arguments comme l''exemple suivant :
[code lg="bash"]
psql -f myfile.sql -U username -d databasename
[/code]

', 'Importation d''un fichier SQL dans une base de données.', '2018-03-19 16:20:18 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'b58bda0b-2f45-4c7a-8ece-1a206fb32a7a'),
('d74fc919-9f1b-4672-af81-ae6b6bca0cbd', 'POSTUFCGBYW29V', 'Installation d''un serveur DHCP sous Debian 8', '[h1]Introduction[/h1]
Le serveur est  une machine virtuelle. Il dispose de deux cartes ethernets.
Nous partons du principe que vous maîtrisez les bases sur Debian ! ;) Les sources des paquets sont donc déjà à jour et les cartes ethernets déjà configurées.
eth0 : 192.168.144.100/24 : La norme est 192.168.1.0/24 mais je mets 144 sur le troisième octet car j''en ai envie :)
eth1 : En DHCP avec mon réseau local afin que le serveur puisse communiquer avec l''extérieur pour avoir un accès à internet.

L''utilisateur utilisé pour ce tuto est un utilisateur qui peut éxécuter des actions en tant que root. En effet, il faut éviter d''utiliser le compte root pour des questions de sécurité.

Le client est une machine Debian qui est dans le même réseau interne 192.168.144.0/24, dont la carte ethernet est configurée en DHCP.


[h1]Installation du paquet[/h1]
On installe le serveur DHCP:
[code lg="bash"]
sudo apt-get install isc-dhcp-server
[/code]

Le service va vouloir démarrer par défaut. Cela va échouer. Il faut adapter la configuration par rapport à notre contexte !

[h1]Configuration du serveur[/h1]
Il faut juste modifier le fichier de configuration principal. Il contient déjà certains paramètres et des commentaires, on peut les effacer: (CTRL + K avec nano pour effacer une ligne)
[code lg="bash"]
sudo nano /etc/dhcp/dhcpd.conf
[/code]

[code lg="bash"]
#Plage d''adresses distribuees
subnet 192.168.144.0 netmask 255.255.255.0
{
	range 192.168.144.1 192.168.144.39;
}

#Masque de sous-réseau
option subnet-mask 255.255.255.0;

#Adresse du serveur DNS (ici, nous n''en n''avons pas)
option domain-name-servers 192.168.144.50;

#Passerelle
option routers 192.168.144.254;

#Nom du domaine
option domain-name "kage.local";

#Temps de renouvellement des bails DHCP en secondes
default-lease-time 3600;
max-lease-time 7200;

#Serveur de temps (là aussi, il n''y en a pas)
option ntp-servers 192.168.144.50;

#Adresse de diffusion
option broadcast-address 192.168.144.255;

#S''il y a un serveur NetBIOS Microsoft
#option netbios-name-servers 192.168.144.50
[/code]

Même si je dispose de plusieurs interfaces, je n''ai pas besoin de spécifier celle utilisée. Le service DHCP saura de lui-même en fonction de notre configuration.
Bien sûr, il existe des options bien plus avancées.

Puis on démarre notre service
[code lg="bash"]
sudo service isc-dhcp-server start
[/code]

On vérifie qu''il est bien démarré et qu''il n''y a pas d''erreur:
[code lg="bash"]
sudo service isc-dhcp-server status
[/code]

[h1]Réception du bail DHCP[/h1]
Le client étant déjà démarré, il a déjà effectué une recherche de serveur DHCP au démarrage.

Deux solutions :
1. On peut demander une adresse DHCP manuellement.
2. On attends un peu et notre client va récupérer une adresse DHCP auprès de notre serveur.

Récupération de l''adresse DHCP manuellement:
Il suffit d''effectuer une demande à l''aide d''un client DHCP. Nous utiliserons celui présent par défaut sous Debian. (Il en existe d''autres)

On vérifie que notre machine cliente n''a pas d''adresse:
[code lg="bash"]
ip a
[/code]

On demande une adresse DHCP:
[code lg="bash"]
sudo dhclient -v eth0
[/code]

dhclient : Nom du client DHCP utilisé
-v : en mode verbeux. Cela permet de suivre l''état de la demande.
eth0 : On spécifie l''interface qui doit recevoir l''adresse.

On vérifie que l''on a bien récupéré une adresse: L''adresse donnée est la première définie dans notre plage.
[code lg="bash"]
ip a
[/code]

On peut effectuer un ping vers notre serveur DHCP:
[code lg="bash"]
ping -c 3 192.168.144.100
[/code]

-c 3 : Spécifie que je n''envoi que 3 pings.

Autre option : Résiliation de l''adresse DHCP
[code lg="bash"]
sudo dhclient -r eth0
[/code]

ip a doit en théorie ne plus retourner d''adresse pour l''interface. Il reste à refaire une demande de bail pour avoir une nouvelle adresse.', 'Installation d''un serveur DHCP sous Debian 8', '2020-01-17 15:05:31 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('c7c6d34b-1be6-4b55-9d2a-aec74608d584', 'POSTREJFVJA8CZ', 'Propriétaire des tables PostgreSQL', '[h1]Problématique[/h1]
Toutes les tables de votre base n''appartiennent pas au même utilisateur.
[h1]Résolution[/h1]
Depuis un terminal, en tant qu''utilisateur "postgres", entrez cette commande suivante :
[code lg="bash"]
for table in `psql -tc "select tablename from pg_tables where schemaname = ''public'';" NOM_DE_LA_BDD` ; do  psql -c "alter table ${table} owner to NOM_UTILISATEUR" NOM_DE_LA_BDD ; done
[/code]

Il vous faudra adapter la commande en modifiant NOM_DE_LA_BDD par le nom de la base de données, et NOM_UTILISATEUR par le nom de l''utilisateur que l''on veut définir comme propriétaire.
[h3]Sources[/h3]
[link href="https://dba.stackexchange.com/questions/52195/postgresql-change-owner-of-all-tables-under-a-specific-schema" txt="https://dba.stackexchange.com/questions/52195/postgresql-change-owner-of-all-tables-under-a-specific-schema" /]', 'Changer le propriétaire de toutes les tables d''une base de données.', '2017-11-27 10:32:36 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'b58bda0b-2f45-4c7a-8ece-1a206fb32a7a'),
('a18aab34-5bd0-481d-8bf2-9c5a7eb8bf11', 'POSTXI1HQ1KJB7', 'Alias de monitoring', '[h1]Introduction[/h1]
Voici 2 alias de la commande "ps" permettant de voir rapidement quels sont les processus les plus gourmands en CPU ou en mémoire.
[h2]Consommation de CPU[/h2]
[code lg="bash"]
alias psproc=''ps -e --format="pid %cpu %mem cmd" --sort pcpu''
[/code]

Cet alias va afficher les colonnes suivantes :
 - PID
 - Consommation CPU
 - Consommation mémoire
 - Commande du processus
Ordre de tri : Consommation CPU par ordre croissant.
[h2]Consommation de mémoire[/h2]
[code lg="bash"]
alias psmem=''ps -e --format="pid %cpu %mem cmd" --sort rss''
[/code]

Cet alias va afficher les colonnes suivantes :
 - PID
 - Consommation CPU
 - Consommation mémoire
 - Commande du processus
Ordre de tri : Consommation mémoire', 'Deux alias permettant d''afficher les processus actifs triés par consommation de CPU et par consommation de mémoire.', '2017-11-29 10:44:42 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('fb05e159-01b8-4efa-a892-bc38215acc56', 'POST3FHSQPG3AP', 'Déploiement d''un fichier war.', '[h1]Avec Maven[/h1]
Maven permet de compiler, exécuter les tests unitaires et de créer un fichier exécutable pour les projets Java.
Avec la configuration par défaut, Maven suffixe ces fichiers en sortie de traitement par le numéro de version définit dans le fichier "pom.xml".
Exemple :
[code lg="bash"]
myProgram-0.0.1-SNAPSHOT.war
[/code]

Ceci a pour conséquence qu''une fois déployée, l''application sera accessible via le nom de ce fichier :
[code lg="markup"]
http://my-server.org/myProgram-0.0.1-SNAPSHOT/
[/code]

[h2]Solution[/h2]
Afin de régler ce problème, il suffit de rajouter la balise "<finalName>" dans le nœud "/project/build/" du fichier "pom.xml" :
[code lg="markup"]
<project ...>
    ...
    <build>
        <finalName>MyProgram</finalName>
        ...
    </build>
</project>
[/code]

L''application sera donc disponible à cet endroit :
[code lg="markup"]
http://my-server.org/MyProgram/
[/code]

[h1]Avec Wildfly[/h1]
Dans le même cas de figure, avec Wildfly, il se peut que eclipse déploie l''archive war avec l''extension "-0.0.1".
[h2]Solution[/h2]
Il suffit de créer un fichier nommé "jboss-web.xml" dans le dossier "/WebContent/WEB-INF/" du projet, avec le contenu suivant :
[code lg="markup"]
<?xml version="1.0" ?>
<jboss-web>
    <context-root>/myProgram</context-root>
</jboss-web>
[/code]

[h3]Source[/h3]
[link href="https://stackoverflow.com/questions/39727675/wildfly-deploy-maven-remove-version?rq=1" txt="https://stackoverflow.com/questions/39727675/wildfly-deploy-maven-remove-version?rq=1" /]
[link href="https://stackoverflow.com/questions/26670926/jboss-how-set-deployment-runtime-name-not-using-cli-but-directly-from-ear-wa" txt="https://stackoverflow.com/questions/26670926/jboss-how-set-deployment-runtime-name-not-using-cli-but-directly-from-ear-wa" /]', 'Définition du nom de l''archive war pour le package créé par Maven ou avec le serveur Wildfly.', '2017-12-03 12:12:43 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '61f9fbf3-3340-4ea4-9661-04089377bb2e'),
('f4554711-a4c9-48ba-b51f-275e600df6a8', 'POSTJH9P4E9797', 'Linux & Firefox - Sélection automatique de l''url', '[h1]Problématique[/h1]
Lorsqu''on installe firefox sous Linux, l''option de sélection automatique de l''URL au gain du focus de la barre d''adresse est désactivée par défaut.
[h1]Solution[/h1]
Aller dans le panneau de configuration en saisissant l''adresse suivante :
[code lg="bash"]
about:config
[/code]

Puis chercher la clef "browser.urlbar.clickSelectsAll", et la définir à "true".
[h3]Source[/h3]
[link href="http://voidandany.free.fr/index.php/firefox-selection-de-lurl-dans-la-barre-dadresse/" txt="http://voidandany.free.fr/index.php/firefox-selection-de-lurl-dans-la-barre-dadresse/" /]', 'Comment réactiver la sélection automatique de l''url entière lors du clic dans la barre d''adresse, sous Linux.', '2018-02-04 18:36:14 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('362fc16b-6e25-4a31-9308-1ef99dac47b1', 'POSTHP7ZYYH65X', 'Memento Bash', '[h1]Shebang[/h1]
Le sheebang permet de définir quel sera l''interpréteur qui sera utilisé pour exécuter le script si on execute le fichier.
Il doit être définit à la première ligne du script.
[code lg="bash"]
#!/bin/sh
[/code]

Exemple :
[code lg="bash"]
./monscript
[/code]

La commande suivante utilisera l''interpréteur définit par le sheebang.
[h1]Arguments[/h1]
[h2]Nom du script[/h2]
[code lg="bash"]
$0
[/code]

Peut être pratique dans le cas où le script est déplacé puis renommé.
[h2]Arguments du script[/h2]
[code lg="bash"]
$1... $n
[/code]

Tous les arguments en une seule variable :
[code lg="bash"]
$@
[/code]

[h2]Code retour[/h2]
[code lg="bash"]
$?
[/code]

Code retour de la précédente commande
[h2]Nombre d''arguments[/h2]
[code lg="bash"]
$#
[/code]

Nombre d''arguments à l''appel du script
[h1]Variables[/h1]
[h2]Déclaration[/h2]
[code lg="bash"]
mavariable=0
[/code]

On peut créer une variable à n''importe quel endroit dans le script.
Note : Il faut absolument ne pas laisser d''espaces entre le nom de la variable et sa valeur d''affectation
[h2]Utilisation[/h2]
Pour exploiter la valeur d''une variable, il faut utiliser l''opérateur "$".
Exemple :
[code lg="bash"]
mavariable=3
echo "Contenu de la variable : $mavariable"
[/code]

Ce qui affichera :
[code lg="bash"]
Contenu de la variable : 3
[/code]

[h2]Portées[/h2]
[h3]Portée par défaut[/h3]
Toutes les variables déclarées sont de portée globale, c''est à dire qu''elle sont accessibles depuis n''importe où dans le script.
Exemple :

[code lg="bash"]
var=3

function test()
{
	echo $var
}

test
[/code]

Le script ci-dessus affichera "3" dans la console.
[h3]Portée "local"[/h3]
En plaçant le mot clef "local" avant la déclaration d''une variable, cette dernière sera disponible que dans la fonction dans laquelle elle sera déclarée.
[code lg="bash"]
function test()
{
	local var=3 # Création de la variable "var"

	if [[ test ]]
	then
		echo $var
	fi
} # Ici la variable "var" sera détruite en mémoire
[/code]

Si on ne met pas le mot clef "local" lors de la déclaration de la variable, celle-ci sera toujours disponible après l''exécution de la fonction.
[code lg="bash"]
function test()
{
	var=3 # Création de la variable "var"
	...
}

echo $var # La variable "var" existe toujours ici
[/code]

[h1]Quotes[/h1]
[h2]Double quotes[/h2]
...', 'Memento sur les bases de la programmation en bash.', '2018-02-22 19:46:50 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('c00bf2c6-7485-4fa8-a7c3-10cb4efe8531', 'POSTAWPDH3RYPY', 'Screen et les processus en arrière plan', '[h1]Problématique[/h1]
Pour lancer des processus en arrière plan, il suffit d''ajouter le caractère "&" à la fin de la commande afin qu''elle s''exécute en arrière plan.
Cependant, si on est sur une connexion à distance, via le protocole ssh par exemple (comme avec Putty), la commande lancée en arrière plan sera attachée au terminal distant. Par conséquent, si on ferme la connexion et donc le terminal distant, le processus en arrière plan sera arrêté.

Ceci provient du système d''arborescence des processus :
Lorsqu''on ouvre une connexion à distance via ssh, on créer un processus correspondant à l’interpréteur shell du serveur, que l''on nommera le processus A.
Depuis ce terminal distant (A) on lance une commande en arrière plan, qu''on nommera le processus B.

Dans cette situation, le processus B est un processus enfant du processus A, et ce dernier et le processus parent du processus B.
Si on tue un processus parent, le système va tuer tous ses processus enfants.
[h1]Solution[/h1]
Il existe la commande "screen". Cette dernière va créer des terminaux virtuels qui vont être distincts du processus qui les a créer.
[h2]Créer un terminal virtuel[/h2]
Il suffit de taper la commande "screen".
[code lg="bash"]
$ screen
[/code]

On peut également définir un nom au terminal virtuel grâce à l''argument "-S", afin de pouvoir le récupérer plus facilement lorsqu''il sera en arrière plan :
[code lg="bash"]
screen -S MonSuperTerminalVirtuel
[/code]

[h2]Placer le terminal en arrière plan[/h2]
Une fois le terminal virtuel créé, on peut démarrer un processus long, puis taper sur les commandes "ctrl+A" puis taper sur la touche "D" afin de placer le processus en arrière plan.
[h2]Lister les terminaux virtuels en arrière plan[/h2]
Il suffit d''utiliser l''argument "-ls" de la commande "screen" :
[code lg="bash"]
screen -ls
[/code]

Exemple :
[code lg="bash"]
$ screen -ls
There are screens on:
	16947.MonSuperTerminal2	(02/03/2018 14:35:21)	(Detached)
	16933.MonSuperTerminal1	(02/03/2018 14:35:18)	(Detached)
2 Sockets in /run/screen/takiguchi.
[/code]

[h2]Récupérer un processus en arrière plan[/h2]
Il suffit d''utiliser l''argument "-r" de la commande "screen" :
[code lg="bash"]
screen -r
[/code]

S''il n''y a qu''un seul terminal virtuel en arrière plan, l''argument "-r" peut être employé seul.
S''il y a plusieurs terminaux virtuels, il faudra ajouter l''identifiant du terminal après l''argument "-r".
Exemple reprenant le cas précédent :
[code lg="bash"]
screen -r 16947
[/code]

La valeur "16947" correspond à l''identifiant du terminal, qu''on peut récupérer via la commande "screen -ls" :
[code lg="bash"]
$ screen -ls
There are screens on:
 -->16947.MonSuperTerminal2	(02/03/2018 14:35:21)	(Detached)
	16933.MonSuperTerminal1	(02/03/2018 14:35:18)	(Detached)
2 Sockets in /run/screen/takiguchi.
[/code]

[h3]Sources[/h3]
[link href="https://doc.ubuntu-fr.org/screen" txt="https://doc.ubuntu-fr.org/screen" /]', 'Lancer des processus en arrière plan avec la commande screen.', '2018-03-02 14:43:20 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('e36368b2-daaa-4b82-b0cc-a0ac754f68ff', 'POSTS6WF0FGD50', 'Memento plpgsql', '[h1]Variables[/h1]
[h2]Création[/h2]
Il faut déclarer la variable dans la section "DECLARE" du script plpgsql.
[code lg="sql"]
...
DECLARE
    ma_variable type;
BODY
...
[/code]

[h2]Affectation d''une valeur[/h2]
[code lg="sql"]
ma_variable := valeur;
[/code]

[h1]Boucles[/h1]
[h2]Boucler sur le résultat d''une requête[/h2]
[code lg="sql"]
...
DECLARE
    var_objetTmp nomTable%rowtype;
BEGIN
    FOR var_objetTmp IN
        SELECT * FROM nomTable;
    LOOP
        ...
    END LOOP;
...
[/code]


[h2]Boucler sur le résultat d''une requête stocké dans une variable[/h2]
Pour stocker le résultat d''une requête dans une variable, il faut que cette variable soit du type "CURSOR".
Il faudra également une seconde variable, de type "RECORD" afin de récupérer l''objet en cours d''itération.
Exemple :
[code lg="sql"]
...
DECLARE
    c_monCursor CURSOR FOR SELECT * FROM nomTable;
    c_monCursorAvecParametres CURSOR(p_paramRequete type) FOR
            SELECT * FROM nomTable WHERE critere = p_paramRequete);

    var_objetTmp RECORD;
BEGIN
    -- Ouverture du cursor afin de récupérer le résultat de sa requête
    OPEN c_monCursorAvecParametres(1);
    <<tagLoop>> -- Sert à identifier la boucler à stoper en cas d''instruction "EXIT"
    LOOP
        -- Récupération de l''itérateur
        FETCH c_monCursorAvecParametres INTO var_objetTmp;
        EXIT tagLoop WHEN NOT FOUND OR autreCondition;
        ...
    END LOOP;
...
[/code]

', 'Memento sur les bases du plpgsql', '2018-03-21 09:57:02 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'b58bda0b-2f45-4c7a-8ece-1a206fb32a7a'),
('7853a397-7bec-41fc-aee6-67e73e2c196a', 'POSTILZABNVYNR', 'Afficher qu''une partie d''un fichier texte', '[h1]Commande[/h1]
[code lg="bash"]
cat fichier.log | tail -n <1ere ligne interval> | head -n <dernière ligne interval>
[/code]

[h1]Exemple[/h1]
[code lg="bash"]
cat fichier.log | tail -n 1000 | head -n 100
[/code]

Affiche les 100 lignes à partir de la 1000ème ligne en partant de la fin.', 'Utilisation de la commande tail pour n''afficher qu''une partie d''un fichier texte.', '2018-04-24 11:03:25 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('18e77cff-7eca-4c49-8b82-01222892161f', 'POST2VJC5XZTIU', 'Correction du bug de changement des droit d''Administrateur (MacOS High Sierra)', '
[h2]Présentation du problème[/h2]


Lorsque vous lancez l''installation d''un .dmg sur votre Mac, ce dernier va vous demander un nom d''utilisateur et un mot de passe d''un compte qui détient les droits d''administrateur. Lorsque vous êtes sur la session qui détient ces droits, il vous affiche alors une fenêtre avec votre nom d''utilisateur déjà prérempli, et vous n''avez qu''a renseigner le mot de passe de votre session.
Il se peut qu''un bug survienne et vous empêche de lancez toutes actions qui demandent des droit d''administrateur. Pour l''observer :

Rendez vous dans Préférences système > Utilisateur & Groupes :
Ce que vous devriez avoir :
[img src="./images-uploaded/uSWyBvloFf9YGIhgo6lP19EtVAFVNn" /]

Ce que le bug va rendre :
[img src="./images-uploaded/grKrpMQZNNQqkbs2GChoTDuXrqAYmS" /]

Le soucis c''est que vous pouvez voir dans la liste des utilisateurs de cet ordinateur, il n''y a aucun administrateur. Cela va donc vous empêcher de lancer des actions qui demandent des droits d''administrateurs.

Par exemple, lorsque vous tentez une installation avec un compte administrateur :
[img src="./images-uploaded/GxLmSSSfUoAyMgQi74YBjIA64bY88Y" /]

Mais quand le bug survient :
[img src="./images-uploaded/Vm0UcQBtIZcBlyDfZo7lh2LlvHWQp5" /]

Le soucis c''est que peu importe le compte utilisateur que vous rentrerez, il vous dira que ce n''est pas le bon compte, même si vos login et mot de passe sont correctes.


[h2]Résolution du problème[/h2]

Démarrez en mode Recovery :
[ command ] + R au démarrage, avant l''apparition de la pomme.

Un menu avec plusieurs option va apparaitre, choisissez l''Utilitaire de disque.
Votre volume Macintosh HD apparait alors comme grisé, non monté.

Sélectionnez le, et cliquez sur le bouton plus haut [ Monter ].

Une fois fait, il va vous demander votre mot de passe, celui permettant d''ouvrir votre Session, faites le.
Vous pouvez maintenant voir que votre volume Macintosh HD est disponible et est monté. Vous devez alors quitter l''Utilitaire de disque.

Une fois de retour au menu du mode Recovery, dans la barre supérieur de l''écran, allez dans Utilitaire > Terminal.

Il va falloir rentrer la commande suivante dans le terminal qui vient de se lancer :

[code lg="bash"]
rm /Volumes/"Macintosh HD"/private/var/db/.AppleSetupDone
[/code]

Il faut le copier avec les espaces et majuscules comme indiqué ci-dessus. (avec exactitude !)

Cette commande va supprimer le fichier que MacOS créé lorsque vous lancez la configuration de votre Macbook pour la première fois. Dans ce fichier était renseigné le nom de l''utilisateur admin qui avait les droits d''administrateur. Cet utilisateur à été supprimé c''est pour cela que vous ne pouviez plus y avoir accès.

Redémarrez ensuite votre mac dans le menu, cette fois sans toucher au clavier. Vous allez avoir votre page de session normale, authentifiez vous normalement, et le mac va vous demander de le reconfigurer comme au début, lorsque vous l''aviez ouvert pour la première fois. Suivez les instructions jusqu''à la fin où il va vous demander de créer un compte admin.

Ne surtout pas mettre les même informations que votre compte principale, choisissez quelque chose de simple car nous le supprimeront à la fin.

Par exemple :
Nom complet = "admin"
Nom de compte = "admin"
Mot de passe = "[REDACTED]
Indication mot de passe = "[REDACTED] à Nom complet"

J''ai choisis "admin" mais "toto" fait aussi bien l''affaire.

Vous voila alors dans la session "admin" (ou "toto") qui a les droits d''administrateur.
Allez dans Préférences Système > Utilisateurs & groupes et cliquez sur le cadenas en bas à gauche pour le déverrouiller. Renseignez le mot de passe du compte admin.
Sélectionnez votre compte principale dans la liste (celui qui est devenu Standard) et cochez "Autoriser l''administration de cet ordinateur."

Sortez de la session "admin" et allez dans la votre, vous venez de retrouver tout vos droits d''administrateur.
Libre à vous de supprimer votre compte "admin" car il n''est plus utile ou de le garder en cas d''incident.
', 'Disparition de vos droits d''administrateur sur votre compte', '2018-05-01 15:44:06 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '2073a7eb-b3e5-4b33-855d-067c8350eddb', '7234cd9e-3834-45c5-973b-1574f5c3c4c6'),
('8185f36a-26fb-463f-84cb-490e5dd629a5', 'POSTYRTKG82FM3', 'Développer en PHP sous OSX', '[h1]Préambule[/h1]
L''interpréteur PHP est déjà installé par défaut sous OSX, il faut cependant l''activer manuellement.
[h1]Apache et PHP[/h1]
[h2]Activer l''interpréteur PHP[/h2]
Il suffit de taper la commande suivante :
[code lg="bash"]
sudo apachectl start
[/code]

[h2]Configurer Apache[/h2]
Faites une sauvegarde du fichier de configuration par défaut :
[code lg="bash"]
sudo cp /etc/apache2/httpd.conf /etc/apache2/httpd.conf.sav
[/code]

Ensuite il faut dire à apache de démarrer PHP avec lui, en éditant le fichier "httpd.conf" en décommentant la ligne suivante :
[code lg="bash"]
LoadModule php7_module libexec/apache2/libphp7.so
[/code]

Pour tester la configuration, on peut créer un fichier "phpinfo.php" dans le répertoire suivant : "/Library/WebServer/Documents/"
[code lg="php"]
<?php phpinfo(); ?>
[/code]

[h1]Installer XDebug[/h1]
[h2]Compilation[/h2]
Téléchargez les sources de l''extension xdebug ici : [link href="https://xdebug.org/files/xdebug-2.7.0alpha1.tgz" txt="Télécharger" /]
Il faut ensuite les extraire dans un répertoire, disons dans votre dossier "Téléchargements".

Puis, ouvrir un terminal et se placer dans ce répertoire :
[code lg="bash"]
cd ~/Téléchargements
[/code]

Ensuite, il faut préparer la compilation à l''aide de la commance "phpize" :
[code lg="bash"]
phpize
[/code]

Si une erreur s''affiche en disant qu''il est impossible de trouver "autoconf", il faut l''installer, notamment via HomeBrew.

[h3]HomeBrew[/h3]
Il faut installer HomeBrew pour pouvoir installer autoconf facilement.
Pour cela, tapez la commande suivante dans le terminal :
[code lg="bash"]
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
[/code]

Une fois terminé, vous pouvez installer "autoconf" via la commande suivante :
[code lg="bash"]
brew install autoconf
[/code]

Une fois la parenthèse "HomeBrew" terminé, on continue la compilation de l''extension avec les deux commandes suivantes :
[code lg="bash"]
./configure
make
[/code]

[h2]Installation[/h2]
Une fois la compilation terminé, la commande "make" vous suggèrera d''installer l''extension via la commande "make install". NE LE FAITES PAS !

Il faut plutôt copier l''extension dans un répertoire du système, comme dans "/opt/php/extensions" :
[code lg="bash"]
# Création du répertoire
sudo mkdir -p /opt/php/extensions/
# Copie de l''extension, depuis le répertoire de compilation
sudo cp ./modules/xdebug.so /opt/php/extensions/
[/code]

Voilà, l''extension est installé, il faut maintenant la configurer.
[h1]Configuration[/h1]
Tout se passe dans le fichier "/etc/php.ini".
Il se peut que par défaut, il n''existe pas, mais qu''un fichier "/etc/php.ini.default" soit présent.
Il suffit d''en faire une copie dans "/etc/" :
[code lg="bash"]
sudo cp /etc/php.ini.default /etc/php.ini
[/code]

Une fois copié, il faut éditer le fichier et ajouter les lignes suivantes à la fin du fichier :
[code lg="bash"]
zend_extensions = /opt/php/extensions/xdebug.so

[XDebug]
xdebug.remote_enable = 1
xdebug.remote_autostart = 1
[/code]

Enfin, il faut redémarrer le service apache :
[code lg="bash"]
sudo apachectl restart
[/code]

', 'Installer PHP ainsi que xdebug sous OSX', '2018-05-09 18:31:29 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '7234cd9e-3834-45c5-973b-1574f5c3c4c6'),
('a56d3ae1-89aa-4026-93aa-67a337286149', 'POSTP6MDNFDK92', 'Permissions apache avec OSX', '[h1]Problématique[/h1]
Si on créer un projet PHP et qu''on créer un lien vers de dernier dans le workspace d''apache, ce dernier vous indiquera qu''il n''a pas les droits d''accès (Permission denied 403) aux fichiers (php, html etc.).
[h1]Solution[/h1]
Il suffit de définir l''option "Dossier partagé" depuis une fenêtre finder :
[img src="./images-uploaded/3NtcAPGLdWHVCXhHNlFxCAxzpswcyZ" /]', 'Corriger les problèmes de droits d''accès d''apache pour les fichiers à travers des liens symboliques sous OSX', '2018-05-09 18:40:55 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '7234cd9e-3834-45c5-973b-1574f5c3c4c6'),
('3f3b287d-f287-43c2-82b7-35162c5933b6', 'POSTRXTCPSEF97', 'Débugger avec Angular, VSCode et Chromium', '[h1]Installer l''extension VSCode[/h1]
Dans un premier temps, il faut installer l''extension "VSCode-chrome-debug", dont les instructions d''installation sont présentes à cette adresse : [link href="https://github.com/Microsoft/vscode-chrome-debug" txt="https://github.com/Microsoft/vscode-chrome-debug" /]

[h1]Configuration de VSCode[/h1]
Il faut modifier le fichier de configuration "launch.json" présent dans le dossier ".vscode" du projet, et y ajouter les configurations suivantes :
[code lg="markup"]
{
	"name": "ng serve",
	"type": "chrome",
	"request": "launch",
	"url": "http://localhost:4200/#",
	"webRoot": "${workspaceFolder}"
},
{
  "name": "ng test",
  "type": "chrome",
  "request": "launch",
  "url": "http://localhost:9876/debug.html",
  "webRoot": "${workspaceFolder}",
  "runtimeExecutable": "/usr/bin/chromium"
},
{
  "name": "ng e2e",
  "type": "node",
  "request": "launch",
  "program": "${workspaceFolder}/node_modules/protractor/bin/protractor",
  "protocol": "inspector",
  "args": ["${workspaceFolder}/protractor.conf.js"]
}
[/code]

[h2]Détection de Chromium[/h2]
Si VSCode ne détecte pas Chromium, il faut le lui déclarer dans les parties "configuration" du fichier "launch.json", via l''attribut "runtimeExecutable" comme dans l''exemple suivant :
[code lg="markup"]
{
  "name": "ng test",
  "type": "chrome",
  "request": "launch",
  "url": "http://localhost:9876/debug.html",
  "webRoot": "${workspaceFolder}",
  "runtimeExecutable": "/usr/bin/chromium"
}
[/code]

[h1]Démarrage des services[/h1]
[h2]Serveur ng[/h2]
Il faut démarrer le serveur de dev d''angular via la commande "npm test" et non via la commande "ng test".

[h2]Chromium[/h2]
Il faut démarrer Chromium en lui disant de lancer son service de débogage comme l''argument suivant :
[code lg="bash"]
/usr/bin/chromium %U --remote-debugging-port=9222
[/code]

[h3]Sources[/h3]
[link href="https://github.com/Microsoft/vscode-chrome-debug" txt="https://github.com/Microsoft/vscode-chrome-debug" /]', 'Mise en place du débogage de code Angular avec l''éditeur Visual Studio Code et Chromium.', '2018-05-26 19:26:55 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '49b4df8a-19f5-459b-b508-6b7c71332523'),
('08c5ff23-dc9b-4af9-adfc-ed3c0d405e34', 'POSTQ7VJCQSQWT', 'Random string', '[h1]Commande[/h1]
[code lg="bash"]
head /dev/urandom | tr -dc A-Za-z0-9 | head -c <length> ; echo ''''
[/code]

Il faut remplacer "<length>" par la longueur de la chaîne souhaitée.
[h3]Source[/h3]
[link href="https://unix.stackexchange.com/questions/230673/how-to-generate-a-random-string" txt="https://unix.stackexchange.com/questions/230673/how-to-generate-a-random-string" /]', 'Générer une chaîne aléatoire dans un terminal bash', '2018-05-26 19:29:59 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('eb5752dd-a15d-451f-b404-27ae95918529', 'POSTUCWKMM5LZQ', 'Git avec SSH et des ports custom', '[h1]Problématique[/h1]
Lorsqu''on est dans la situation suivante : On a un serveur git du type "gitab", "gogs", "gitea", etc. hébergé chez soi, et qu''on a mis en place une redirection de ports afin d''y accéder en SSH depuis l''extérieur, le port publique SSH pour puller et pusher les modifications du dépôt git est différent du port 22 (port par défaut du protocole SSH).

Il est donc nécessaire d''ajouter une configuration SSH pour indiquer au système quel port utiliser pour communiquer avec le serveur git à travers le port alternatif.
[h1]Solution[/h1]
Côté client (git) il faut créer/modifier le fichier "~/.ssh/config" et ajouter les lignes suivantes :
[code lg="bash"]
Host <ipPubliqueDuServeurGit>
Port <portPubliqueDuServeurGit>
User <utilisateurSshGit>
[/code]

Exemple :
Imaginons que l''ip publique du serveur est "1.2.3.4", que le port publique sur lequel est exposé le protocole SSH est "12345", et que l''utilisateur utilisé par le serveur git est "gituser", il faudra définir les lignes comme ce qu''il suit :
[code lg="bash"]
Host 1.2.3.4
Port 12345
User gituser
[/code]

', 'Configurer sa connexion SSH afin d''intéragir avec un serveur git, disponible via un port différent de celui par défaut.', '2018-05-27 09:36:04 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('581455b4-ec0a-4ffd-bbb9-da365b9e044a', 'POST5RRN4E0NKV', 'Lancement d''un logiciel au démarrage sous Linux', '[h1]Réalisation[/h1]
L''idée est de définir un script shell qui sera exécuté par l''utilisateur root au démarrage du système Linux.
Pour celà, il faut écrire un script shell, en voici un exemple :
[code lg="bash"]
#!/bin/sh
commande_a_executer_au_boot &
[/code]

À partir de là, il faut le copier dans le répertoire "/etc/init.d/" :
[code lg="bash"]
sudo cp ./my_script.sh /etc/init.d/
[/code]

Ensuite, il faut enregistrer le script dans la liste des scripts à exécuter au boot :
[code lg="bash"]
sudo update-rc.d my_script.sh defaults
[/code]

', 'Configurer le démarrage automatique d''un logiciel au démarrage d''un système Linux', '2018-06-06 22:01:55 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('332f860a-7f8c-475a-b691-7f6ea3c790c0', 'POSTS44LEX7O8B', 'Installer les polices Microsoft sous Linux', '[h1]Problématique[/h1]
Sous Linux, les polices tel qu''Arial ne sont pas installées.
[h1]Solution[/h1]
[code lg="bash"]
sudo apt-get install ttf-mscorefonts-installer
[/code]

[h1]Vérification[/h1]
La commande suivante permet de vérifier si la police d''écriture Arial est bien présente sur le système :
[code lg="bash"]
sudo fc-cache
[/code]

[h3]Source[/h3]
[link href="https://askubuntu.com/questions/651441/how-to-install-arial-font-in-ubuntu" txt="https://askubuntu.com/questions/651441/how-to-install-arial-font-in-ubuntu" /]', 'Mémento sur l''installation des polices Microsoft (tel qu''Arial et cie.) sous Linux.', '2018-06-21 09:56:21 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('c521007a-a09a-41f2-9af9-94dcc802193c', 'POSTQUDJ9E799T', 'Teams et les cookies tiers', '[h1]Problème[/h1]
Si vous avez parametré Firefox afin de bloquer tous les cookies tiers (figure 1), l''application Microsoft Teams ne fonctionnera pas (figure 2) :
[img src="https://176.188.217.1:54444/api/images/Wjgp31XHN0nN9Ra5o40CVTma6Fpz9b" /]
Figure n°1 : Paramètrage Firefox à propos des cookies tiers
[img src="https://176.188.217.1:54444/api/images/bvTCMPbTmvljEqQqYzmHTOfVcVhndg" /]
Figure n°2 : Erreur de Teams sur les cookies tiers
[h1]Solution[/h1]
Il suffit de rentrer "https://login.microsoftonline.com" comme exception dans les cookies autorisés.
[h3]Sources[/h3]
[link href="https://answers.microsoft.com/en-us/msoffice/forum/msoffice_other-mso_winother/microsoft-teams-caught-in-loop-asking-to-disable/000e6602-8396-4514-a864-2807447ac8c0" txt="https://answers.microsoft.com/en-us/msoffice/forum/msoffice_other-mso_winother/microsoft-teams-caught-in-loop-asking-to-disable/000e6602-8396-4514-a864-2807447ac8c0" /]', 'Paramétrage de Firefox pour faire fonctionner Teams alors qu''on refuse tous les cookies tiers', '2018-07-13 17:25:01 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '7234cd9e-3834-45c5-973b-1574f5c3c4c6'),
('04929812-1b44-4dce-9616-67553c066867', 'POSTCWF6SVU11I', 'Configuration du HotSpot sous Gnome-shell', '[h1]Configuration[/h1]
Il faut utiliser la commande suivante :
[code lg="bash"]
nm-connection-editor
[/code]

Ça va démarrer un petit utilitaire graphique permettant de modifier toutes les configurations Wifi :
[img src="https://176.188.217.1:54444/api/images/10yoB5nm3S4g1SpgGdOzsxRieW7YIu" /]
Il suffira de sélectionner l''entrée "Hotspot" puis de cliquer sur la roue crantée pour modifier les paramètres.
[img src="https://176.188.217.1:54444/api/images/Dl2YyzpTCPoPGw11z09nWUeeb7xFPP" /]', 'Modification du SSID, mot de passe et les autres informations du HotSpot sous Gnome-shell.', '2018-08-29 21:50:13 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('2bf992cb-1714-438b-931b-75f3aa78b2d0', 'POST39XK7RDGO9', 'Docker login', '[h1]Problème[/h1]
Lorsqu''on veut télécharger une image docker depuis un hub privé, il faut s''y connecter sous peine d''obtenir une erreur "Authentication is required".
[h1]Solution[/h1]
[h2]Linux[/h2]
[code lg="bash"]
docker login [server]
[/code]

Il suffit de saisir l''adresse URL du hub privé à la place de "[server]".
[h2]Windows[/h2]
Il faut utiliser l''utilitaire "winpty".
', 'Se connecter à un docker-hub privé', '2018-10-02 15:24:19 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('dafa9a91-2a39-4c72-adb4-0c861c85fb25', 'POSTXFV3DV07MC', 'Récupérer une branche distante sur git', '[h1]Récupération de la branche[/h1]
[code lg="bash"]
git checkout -b nom_de_la_branche origin/nom_de_la_branche
[/code]

Si git affiche le message d''erreur suivant :
[code lg="bash"]
git checkout -b optimisation origin/optimisation
fatal: ''origin/optimisation'' n''est pas un commit et une branche ''optimisation'' ne peut pas en être créée depuis
[/code]

Alors il faut taper la commande suivante pour indiquer au dépôt local que la branche n''existe pas :
[code lg="bash"]
git fetch origin nom_de_la_branche
[/code]

[h1]Afficher les branches[/h1]
[h2]Branches locales[/h2]
[code lg="bash"]
$ git branch
* master
[/code]

[h2]Branches distantes[/h2]
[code lg="bash"]
$ git branch -r
  origin/1-2-stable
  origin/2-0-stable
  origin/2-1-stable
  origin/2-2-stable
  origin/3-0-unstable
  origin/HEAD
  origin/master
[/code]


[h2]Toutes les branches[/h2]
[code lg="bash"]
$ git branch -a
* master
  origin/1-2-stable
  origin/2-0-stable
  origin/2-1-stable
  origin/2-2-stable
  origin/3-0-unstable
  origin/HEAD
  origin/master
[/code]

[h1]Récupérer toutes les branches distantes[/h1]
[code lg="bash"]
for remote in `git branch -r | grep -v ''\->''`; do git branch --track ${remote#origin/} $remote; done
[/code]

[h3]Sources[/h3]
[link href="http://gitready.com/intermediate/2009/02/13/list-remote-branches.html" txt="http://gitready.com/intermediate/2009/02/13/list-remote-branches.html" /]', 'Récupération d''une branche distante n''existant pas en local avec git', '2018-12-06 12:04:47 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('124a1a2c-d1eb-48b3-bb97-4411c72ebeb0', 'POSTGS1Q1TNJFZ', 'Docker compose erreur libz.so.1 test', '[img src="/api/images/k3nY18IIoa4RH1D8uxLBN5b0lWiQFs" /]

[h1]Introduction[/h1]
Lorsqu''on utilise la commande "docker-compose", on obtient une erreur de ce genre :
[code lg="bash"]
docker-compose: error while loading shared libraries: libz.so.1: failed to map segment from shared object
[/code]

[h1]Résolution[/h1]
Il suffit de recharger le point de montage de /tmp avec certaines options :
[code lg="bash"]
sudo mount /tmp -o remount,exec
[/code]

[h3]Source[/h3]
[link href="https://zindo.info/docker-compose-error-while-loading-libz-so-1.html" txt="https://zindo.info/docker-compose-error-while-loading-libz-so-1.html" /]', 'Impossible de démarrer docker compose car il indique une erreur de chargement de la lib libz.so.1', '2019-08-08 22:21:06 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('6b77f00a-8993-4c7a-b163-78209c96457f', 'POSTABEJ0HQKHM', 'Activer http2 avec Apache', '[h1]Prérequis[/h1]
Le module http2 d''apache n''est disponible qu''à partir de la version 2.4.17.
Assurez vous d''avoir une version égale ou postérieure à celle ci, sinon ça ne fonctionnera pas.
[h1]Installation[/h1]
Il suffit juste d''installer le mode http2 :
[code lg="bash"]
sudo a2enmod http2
[/code]

[h1]Configuration[/h1]
Dans les fichiers de configuration des sites desservis par apache, il suffit de rajouter la configuration suivante :
[code lg="bash"]
<VirtualHost *:443>
    ...
    Protocols h2 http/1.1
    ...
</VirtualHost>
[/code]

[h1]Sources[/h1]
[link href="https://www.skyminds.net/serveur-dedie-mettre-a-jour-apache-et-configurer-le-mod_http2-pour-http2/" txt="https://www.skyminds.net/serveur-dedie-mettre-a-jour-apache-et-configurer-le-mod_http2-pour-http2/" /]', 'Configuration Apache pour activier le protocole http2.', '2019-08-26 14:23:22 +01:00', '446a65ff-2f00-4705-875d-28df1f656204', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('1e93e5e7-8690-4bfe-9250-f9111f455832', 'POST3BG8L6KO8U', 'Exécution d''un script sur MongoDB', '
[code lg="bash"]
mongo <database> -u <username> -p <password> --authenticationDatabase admin <script.js>
[/code]

', 'Exécution d''un script sur MongoDB', '2019-10-04 09:37:06 +01:00', 'f80e0938-8857-4214-bbaf-8a277b91a772', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('97fb806d-8673-40a3-93c7-fcc37344469a', 'POSTM1F5G5OJZD', 'Conteneur PostgreSQL sous Docker', '[h1]Problématique[/h1]
Vous voulez créer un dump d''une base de données présente dans un conteneur docker, ou vous voulez restaurer un dump sur votre base de données présente dans un conteneur docker.

La problématique est que le conteneur dispose de son propre file system, qui n''est pas relié au file system de l''hôte (sans argument "-v" à la création du conteneur). Il est donc difficile de transférer un fichier de l''hôte vers le conteneur et inversement.
[h1]Exporter une base de données[/h1]
Pour créer un dump, depuis un terminal du système hôte, il suffit de taper la commande suivante :
[code lg="bash"]
docker exec <container_name> pg_dump -d <db_name> > ./backup
[/code]

[h1]Importer une base de données[/h1]
Pour restaurer un dump, depuis un terminal du système hôte, il suffit de taper la commande suivante :
[code lg="bash"]
docker exec -i <container_name> pg_restore --dbname=<db_name> --verbose --clean < <dump_file_path>
[/code]

[code lg="sql"]
docker exec -i <container_name> psql -d <database> -U <user> < <dump_file>
[/code]

[h3]Sources[/h3]
[link href="http://durandom.de/docker/postgres/2016/12/20/pg_dump/" txt="http://durandom.de/docker/postgres/2016/12/20/pg_dump/" /]
[link href="https://stackoverflow.com/questions/30171063/how-to-generate-a-postgresql-dump-from-a-docker-container" txt="https://stackoverflow.com/questions/30171063/how-to-generate-a-postgresql-dump-from-a-docker-container" /]
[link href="https://stackoverflow.com/questions/24718706/backup-restore-a-dockerized-postgresql-database" txt="https://stackoverflow.com/questions/24718706/backup-restore-a-dockerized-postgresql-database" /]', 'Importer et exporter une base de données avec un docker PostgreSQL', '2019-08-23 21:22:23 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('569d9633-ee50-45b5-b253-42d625882972', 'POST15UG2MIB1E', 'Reverse proxy apache2 et sécurisation Let''s encrypt', '[h1]Introduction[/h1]
L''idée est d''installer un serveur apache2, et de le configurer en tant que reverse proxy pour desservir plusieurs applications, tout en sécurisant les connexions avec le client grâce à un certificat Let''s encrypt, et en sécurisant les connexions avec les applications proxifiées grâce à des certificats OpenSSL.
[img src="/api/images/995ULXFw1XZ7L1XPP6Gbp3sNoVgb3v" /]

[h2]Installation apache2[/h2]
[code lg="bash"]
sudo apt install apache2
[/code]

Ensuite il faut installer plusieurs modules pour qu''apache puisse servir de reverse proxy :
[code lg="bash"]
sudo a2enmod proxy \\
&& sudo a2enmod proxy_http \\
&& sudo a2enmod ssl \\
&& sudo a2enmod rewrite
[/code]

[h2]Générer un certificat OpenSSL[/h2]
Pour une application de type Java :
[code lg="bash"]
keytool -genkeypair -alias <alias_applicatif> -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 365
[/code]

Pour les autres :
[code lg="bash"]
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
[/code]

Il faudra ensuite configurer l''application afin qu''elle démarre en mode https et en utilisant le certificat généré.

[h2]Générer un certificat Let''s encrypt[/h2]
[h3]Instalation de certbot-auto[/h3]
[code lg="bash"]
wget https://dl.eff.org/certbot-auto
chmod a+x certbot-auto
[/code]

Le mieux est de placer cet outil dans un répertoire dédié car il servira mensuellement à renouveller les certificats, car les certificats Let''s encrypt ne sont valides que pendant 90 jours !
Vous pouvez le mettre dans :
[code lg="bash"]
/opt/certbot/certbot-auto
[/code]

[h3]Génération d''un certificat[/h3]
[code lg="bash"]
sudo ./certbot-auto certonly --domain <nom_de_domaine_pour_le_certificat> --email <mail_de_l_admin>
[/code]

[h2]Configuration des redirections chiffrées[/h2]
[h3]Emplacement du fichier de configuration[/h3]
Il faut créer un fichier ayant un nom respectant le patron suivant :
[code lg="bash"]
/etc/apache2/sites-available/<nom_de_domaine>.conf
[/code]

Ce qui donne par exemple :
[code lg="bash"]
/etc/apache2/sites-available/my-web-site.org.conf
[/code]

[h3]Contenu du fichier de configuration[/h3]
[code lg="bash"]
<VirtualHost *:80>
	ServerName my-web-site.org
	DocumentRoot /var/www/html

	LogLevel warn
	ErrorLog ${APACHE_LOG_DIR}/my-web-site.org-error.log
	CustomLog ${APACHE_LOG_DIR}/my-web-site.org-access.log combined

	RewriteEngine On
	RewriteCond %{HTTPS} !on
	RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

<VirtualHost *:443>
	ServerName my-web-site.org

	SSLEngine on
	SSLCertificateFile /etc/letsencrypt/live/my-web-site.org/cert.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/my-web-site.org/privkey.pem
	SSLCertificateChainFile /etc/letsencrypt/live/my-web-site.org/chain.pem
	SSLProtocol all TLSv1 TLSv1.1 TLSv1.2
	SSLHonorCipherOrder on
	SSLCompression off
	SSLOptions +StrictRequire

	SSLProxyEngine On
	SSLProxyCheckPeerCN Off
	SSLProxyCheckPeerName Off
	SSLProxyVerify none

	ProxyPreserveHost On
	ProxyRequests off
	AllowEncodedSlashes NoDecode
	ProxyPass / https://<ip_du_serveur>:<port>/ nocanon
	ProxyPassReverse / https://<ip_du_serveur>:<port>/

	LogLevel warn
	ErrorLog ${APACHE_LOG_DIR}/my-web-site.org-error.log
	CustomLog ${APACHE_LOG_DIR}/my-web-site.org-access.log combined
</VirtualHost>
[/code]

Ensuite, il faut créer un lien symbolique dans un dossier d''apache afin qu''il le desserve :
[code lg="bash"]
sudo ln -s /etc/apache2/sites-available/my-web-site.org.conf /etc/apache2/sites-enabled/
[/code]

Une fois fait, il faut redémarrer apache pour qu''il charge la nouvelle configuration :
[code lg="bash"]
sudo service apache2 restart
[/code]

[h2]Renouvellement automatique des certificats[/h2]
Il suffit de créer ce script :
[code lg="bash"]
#!/bin/bash
/opt/certbot/certbot-auto renew
[/code]

Et de le placer ici :
[code lg="bash"]
/etc/cron.monthly/
[/code]

[h1]Sources[/h1]
Let''s encrypt :
[link href="https://www.memoinfo.fr/tutoriels-linux/configurer-lets-encrypt-apache/" txt="https://www.memoinfo.fr/tutoriels-linux/configurer-lets-encrypt-apache/" /]
Configuration apache2 comme reverse proxy :
[link href="https://www.digitalocean.com/community/tutorials/how-to-use-apache-as-a-reverse-proxy-with-mod_proxy-on-ubuntu-16-04" txt="https://www.digitalocean.com/community/tutorials/how-to-use-apache-as-a-reverse-proxy-with-mod_proxy-on-ubuntu-16-04" /]
[link href="https://www.vincentliefooghe.net/content/apache-reverse-proxy-https" txt="https://www.vincentliefooghe.net/content/apache-reverse-proxy-https" /]
Génération certificats Java :
[link href="https://www.baeldung.com/spring-boot-https-self-signed-certificate" txt="https://www.baeldung.com/spring-boot-https-self-signed-certificate" /]', 'Mise en place d''un serveur apache2 servant de reverse proxy tout en chiffrant les connexions de bout en bout avec l''application proxifiée.', '2019-08-27 19:57:02 +01:00', '19bcb3b2-199a-4c68-9257-e33a81985ef5', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('70816750-e872-46f0-8ddb-31d90a4a2361', 'POSTZZEQEXBMFS', 'Installation d''un serveur DHCP sous Debian 10', '[h1]Contexte[/h1]
Le serveur est une machine virtuelle. Il dispose de deux cartes ethernets.

enp0s3 : 192.168.1.100/24 ==> Nommage réseau classique réseau d''une PME
enp0s8 : En Nat avec mon réseau local afin que le serveur puisse communiquer avec l''extérieur pour avoir un accès à internet.
L''IP Forwarding a également été activé en interne dans la machine virtuelle.

Le nommage des cartes est celui utilisé par défaut depuis Debian 9. Je l''ai donc conservé et n''ai pas cherché à renommer les cartes, action qui malgré tout  reste possible

L''utilisateur utilisé pour ce tuto est un utilisateur qui peut exécuter des actions en tant que root. En effet, il faut éviter d''utiliser le compte root pour des questions de sécurité.

Le client est une machine Debian sans interface graphique qui est dans le même réseau interne 192.168.1.0/24, dont la carte ethernet est configurée en DHCP.


[h1]Installation du paquet[/h1]
On installe le serveur DHCP:
[code lg="bash"]
sudo apt-get install isc-dhcp-server
[/code]

Le service va vouloir démarrer par défaut. Cela va échouer. Il faut adapter la configuration par rapport à notre contexte.
L''erreur retourne le message suivant : "Failed to start LSB: DHCP server."

[h1]Configuration du serveur[/h1]
Il faut modifier le fichier de configuration principal. Il contient déjà certains paramètres et des commentaires, on peut les effacer: (CTRL + K avec nano pour effacer une ligne ou dd avec vi & vim)

Certains paramètres sont laissé volontairement commenté car je n''ai pas les éléments dans mon environnement mais j''inscris ces options pour montrer qu''elles existent.

[code lg="bash"]
sudo nano /etc/dhcp/dhcpd.conf
[/code]

[code lg="bash"]
#Plage d''adresses distribuees
subnet 192.168.1.0 netmask 255.255.255.0
{
        range 192.168.1.1 192.168.1.39;
}

#Masque de sous-réseau
option subnet-mask 255.255.255.0;

#Adresse du serveur DNS
#option domain-name-servers 192.168.1.100;

#Passerelle
option routers 192.168.1.254;

#Nom du domaine
option domain-name "kage.local";

#Temps de renouvellement des bails DHCP en secondes
default-lease-time 3600;
max-lease-time 7200;

#Serveur de temps
#option ntp-servers 192.168.1.100;

#Adresse de diffusion
option broadcast-address 192.168.1.255;

#Serveur NetBIOS Microsoft
#option netbios-name-servers 192.168.1.50
[/code]

Même si je dispose de plusieurs interfaces, je n''ai pas besoin de spécifier celle utilisée. Le service DHCP saura de lui-même en fonction de notre configuration.
Bien sûr, il existe des options bien plus avancées.

Puis on démarre notre service
[code lg="bash"]
systemctl start isc-dhcp-server
[/code]

On vérifie qu''il est bien démarré et qu''il n''y a pas d''erreur:
[code lg="bash"]
systemctl status isc-dhcp-server
[/code]

Note : A l''heure ou est publié cet article, il semble y avoir un bug sur le paquet isc:
En effet, le service apparait en status "failed" mais un processus est bien généré (ps -ef | grep dhcp)
Ma machine client, elle, récupère bien adresse IP, voir donc suite du tuto

Version Debian : 10.2
Version du package : 4.4.1-2 amd64 (sudo apt list | grep isc-dhcp)

[h1]Réception du bail DHCP[/h1]
Le client étant déjà démarré, il a déjà effectué une recherche de serveur DHCP au démarrage.

Deux solutions :
1. On peut demander une adresse DHCP manuellement.
2. On attend un peu et notre client va récupérer une adresse DHCP auprès de notre serveur.

Récupération de l''adresse DHCP manuellement:
Il suffit d''effectuer une demande à l''aide d''un client DHCP. Nous utiliserons celui présent par défaut sous Debian : dhclient (Il en existe d''autres)

On vérifie que notre machine cliente n''a pas d''adresse:
[code lg="bash"]
ip a
[/code]

On demande une adresse DHCP:
[code lg="bash"]
sudo dhclient -v enp0s3
[/code]

dhclient : Nom du client DHCP utilisé
-v : en mode verbeux. Cela permet de suivre l''état de la demande et ou elle passe excatement
enp0s3 : On spécifie l''interface qui doit recevoir l''adresse.

Voici les informations que l''on doit obtenir avec le mode verbeux:
[code lg="bash"]
DHCPDISCOVER on enp0s3 to 255.255.255.255 port 67 interval 4
DHCPOFFER of 192.168.1.1 from 192.168.1.100
DHCPREQUEST for 192.168.1.1 on enp0s3 to 255.255.255.255 port 67
DHCPACK of 192.168.1.1 from 192.168.1.100
[/code]

On vérifie que l''on a bien récupéré une adresse: L''adresse donnée est la première définie dans notre plage.
[code lg="bash"]
ip a
[/code]

On peut effectuer un ping vers notre serveur DHCP:
[code lg="bash"]
ping -c 3 192.168.1.100
[/code]

-c 3 : Spécifie que je n''envoi que 3 pings.

Autre option : Résiliation de l''adresse DHCP
[code lg="bash"]
sudo dhclient -r enp0s3
[/code]

ip a n''indique plus d''adresse IP pour l''interface spécifiée. Il reste à refaire une demande pour avoir une nouvelle adresse.', 'Installation d''un serveur DHCP sous Debian 10', '2020-01-17 15:12:33 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('1534f5c5-df57-4cce-9dbc-643e720ed52c', 'POSTHMYL6SKZRP', 'Gestion des fichiers deleted sous Linux', '[h2]C''est quoi un fichier "deleted" ? [/h2]
Sous Linux, il est possible de supprimer un fichier en cours d''utilisation (donc qui a un processus associé). Ce fichier passe alors à l''état "deleted".
Cette action peut être réalisée par n''importe quelle personne qui a les droits nécessaires (propriétaire, membre du groupe, root)

Pour voir les fichiers en cours d''utilisation sur une machine, on utilisera la commande suivante:
[code lg="bash"]
lsof
[/code]

Cette commande va retourner un nombre important de résultats.
Ces fichiers en cours d''utilisation sont localisés dans /proc

Il est possible d’afficher directement les fichiers  "deleted":
 [code lg="bash"]
lsof -nP +L1
[/code]

La page man apporte peu d''informations sur l''explication de ces paramètres mais sont obligatoires

[h2]Les conséquences pour le File System ? [/h2]
Les fichiers qui passent à l''état deleted ne sont plus visibles par le File System via la commande df et du.
Malgré tout, l''espace reste pris par le fichier qui est toujours ouvert dans /proc

J''ai rencontré ce cas concret chez un client où un script est passé, a supprimé un fichier de plusieurs gigas en cours d''utilisation et plus tard, personne ne comprenait pourquoi le FS était plein alors qu''en apparence, il n''y avait rien dessus.


[h2]Reproduction du cas [/h2]
Pour reproduire ce comportement, nous allons générer un fichier, l''ouvrir avec un vi puis le supprimer

On génère un fichier d''une taille suffisamment importante par exemple dans le /home avec la commande dd ( va donner un fichier inexploitable mais c''est juste pour avoir un fichier volumineux):
 [code lg="bash"]
dd if=/dev/zero of=test.txt bs=50000 count=50000
[/code]

if= : ce que je prends en entrée, ici des zéros, contenu sur un pseudo périphérique du système, qui ne contient que des zeros
of= : ce que je vais générer en sortie
bs= : jusqu''à N octets
count = : nombre d''éléments que j''ai pris en entrée donc ici le nombre de zéros, afin de les mettre dans mes octets

La taille indiqué dans le répertoire courant est approximativement de 2Go:
 [code lg="bash"]
du -axm
[/code]

On ouvre un autre shell et on supprime ce fichier. Dans mon cas, je suis owner du fichier donc je peux le supprimer
On affiche les fichiers deleted, marqué par le tag (deleted) :
[code lg="bash"]
lsof -nP +L1
[/code]

[img src="/api/images/eRf3JKRVPewaX14tUcOheVxTCwZwW4" /]

Si on refait la commande df ou du, l''espace reste alloué sur le FS
Dans le cas de notre exemple et juste dans le cas de celui-ci, on a généré un fichier .swp qui permet de récupérer le fichier en cas de coupure brutale du shell (arrêt brutal du serveur). Ce fichier est donc visible mais notre fichier texte lui, ne l''est plus.

[h2]Solution pour débloquer le FS [/h2]

[h3]1.Kill du processus[/h3]
On peut killer le processus via le PID obtenu ou bien redémarrer le service associé.

[h3]2. Contournement[/h3]
Supposons que l''on soit sur un serveur de production et que killer ce processus risque d''impacter les processus liés à celui-ci entraînant ainsi un impact sur la production. On ne va pas prendre le risque de killer le processus ou redémarrer le service associé (Cas vécu)

Pour cela, on va donc réduire la taille du fichier afin de réduire la taille du FS en attendant le bon créneau pour redémarrer le service.

Etapes:
1.Se déplacer dans le répertoire filedescriptor (fd) du processus grâce au numéro de PID:
Ce répertoire contient tous les descripteurs de fichiers liés au processus. Des descripteurs de fichiers sont crées dans la table des descripteurs de fichiers quand un processus est lancé.
Je peux effectuer cette action et me déplacer dans le répertoire file descriptor de ce processus, car je suis propriétaire du fichier donc du processus engendré. Si je n''étais pas propriétaire, je pourrais seulement aller dans /proc/<pid>/ car tout le monde peut y aller et quelques sous répertoires, où tout le monde a le droit de lecture mais pas fd
 [code lg="bash"]
cd /proc/571/fd
[/code]

2.Identifier le lien symbolique (donc le descripteur de fichier) correspondant au fichier supprimé
ls -l
[img src="/api/images/JEYIMM4brxW0s77bSwHeZrU8gblXCc" /]
Ici, c''est le numéro 4
Pour rappel, dans tout autre cas de test autre qu''un vi, le lien appelé 5 ne serait pas présent.

3.Ecrire du vide dans le fichier (donc va permettre de baisser sa taille) en passant par le lien symbolique du file descriptor :
>4

Si l''on refait un df, on verra que la taille du FS aura baissé. Le fichier lui restera toujours dans les fichiers deleted juqu''à l''arrêt du service ou kill du processus
', 'Qu''est qu''un fichier deleted sur Linux, quelles sont les conséquences pour un file System ?', '2020-05-08 15:07:30 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('ab821bb3-199f-4bff-a1b7-1645d3dfd4b0', 'POSTBCH0HKS589', 'Créer une app mac à partir d''un script sh', '[h1]Description[/h1]
Certains logiciels se lancent sous mac via l''exécution d''un script sh.

Il est possible de créer un launcher app de cette application, qui va lancer le script sh lorsqu''on l''exécutera.

[h1]Script de création de launchers[/h1]
Pour se faire, il faut créer un script "appify" à cet emplacement :
[code lg="bash"]
sudo touch /usr/local/bin/appify
[/code]

Note : Vous pouvez lui donner tout autre nom qui vous ferait plaisir.

Ensuite, insérez le contenu suivant :
[code lg="bash"]
#!/usr/bin/env bash
APPNAME=${2:-$(basename "${1}" ''.sh'')};
DIR="${APPNAME}.app/Contents/MacOS";
if [ -a "${APPNAME}.app" ]; then
  echo "${PWD}/${APPNAME}.app already exists. Provide some unique name if you want to create it anyway. ";
  exit 1;
fi;
mkdir -p "${DIR}";
cp "${1}" "${DIR}/${APPNAME}";
chmod +x "${DIR}/${APPNAME}";
echo "${PWD}/$APPNAME.app";
[/code]

Une fois le script créé, il faut le rendre exécutable :
[code lg="bash"]
sudo chmod +x /usr/local/bin/appify
[/code]

[h1]Utilisation[/h1]
Si vous avez créé le script à l''endroit indiqué ci-dessus, vous devriez pouvoir taper la commande "appify" dans un nouveau terminal car le répertoire est normalement dans votre variable "PATH".

Voici comment utiliser le script :
[code lg="bash"]
appify <chemin du fichier sh> "<nom du launcher>"
[/code]

Exemple :
[code lg="bash"]
appify ./umlet.sh "UMLet"
[/code]

Ça va créer un fichier "<nom du launcher>.app" à l''endroit où vous avez exécuté le script "appify".

Ce dernier ce comporte à la fois comme un launcher et comme un dossier.

Optionnel : Si le script sh a besoin d''autres ressources pour fonctionner (fichier exe, jar, images etc.) il faudra les copier dans le répertoire suivant :
[code lg="bash"]
<path du fichier .app>/<nom du launcher>.app/Contents/MacOS/
[/code]

Exemple :
[code lg="bash"]
/Users/<user-id>/Documents/UMLet.app/Contents/MacOS/
[/code]

Enfin, il suffira de déplacer le launcher "app" dans :
[code lg="bash"]
/Library/
[/code]

[h3]Sources[/h3]
[link href="https://techtalkbook.com/create-mac-app-from-a-shell-script/" txt="https://techtalkbook.com/create-mac-app-from-a-shell-script/" /]', 'Créer un raccourci d''application se lançant à partir d''un script shell sous mac', '2022-06-01 14:03:27 +01:00', 'ae3d80a1-5608-4062-bf20-bfed1bf558dc', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'f46fb104-4f53-4732-b33b-6a3ef8c2c0a3'),
('143a79fe-2047-4e3a-b309-508236b56a6c', 'POSTCHWC3MGS27', 'Gestion du SWAP sous Linux', '[h2]C''est quoi un swap ? [/h2]
Le swap (espace d’échange en français) est un espace dédié sur le disque qui va permettre de stocker des pages mémoire, non plus en mémoire mais sur le disque. Certains l''appellent la swap

Avantage:
Cela sert dans le cas ou la mémoire libre de la machine est insuffisante.

Inconvénient :
L''accès à ces pages mémoires y est plus lent

Pour afficher le swap, on utilisera la commande suivante free:
-m : mémoire en mégaoctets
[code lg="bash"]
free -m
                 total        used        free          shared  buff/cache   available
Mem:              483          65           9             1         407           404
Swap:             507           3           504
[/code]

La mémoire ici est de 9 en free. Est-ce critique ? Pas du tout, ce qui est important pour le système est la mémoire available qui est vraiment la mémoire restante. Les pages mémoires souvent utilisées sont mises en buff/cache par Linux afin d’optimiser l''accès, ce qui est le cas ici.

Il peut y avoir plusieurs espaces de swap, on peut les afficher avec la commande swapon -s:
Sur mon serveur, j''en ai uniquement un, qui est le périphérique /dev/dm-1

[code lg="bash"]
swapon -s
Nom de fichier                          Type            Taille  Utilisé Priorité
/dev/dm-1                               partition       520188  3084    -2
[/code]

-s : summary

[h2]La taille d''un swap [/h2]

La taille d''un SWAP doit être définie par rapport à la taille de la mémoire
Ci-dessous les recommandations de Red Hat:

[img src="/api/images/SbjzL36qSwYq7iW27gRrdSsNsUt63A" /]

Les administrateurs Système chez mon client actuel, et moi-même, avons tendance à mettre un espace SWAP égal à la mémoire jusqu''à 32Go de RAM. Au delà de 32Go de mémoire, on considère que l''on est sur des valeurs trop hautes pour continuer à mettre du SWAP et que cela n''apportera rien de plus.

Source Red Hat pour plus d''infos :
https://access.redhat.com/documentation/fr-fr/red_hat_enterprise_linux/7/html/storage_administration_guide/ch-swapspace


[h2]Comment régler la mise en swap ? [/h2]
Le swap fonctionne en se basant sur la mémoire "used" grâce à un fichier de configuration appelé le/la swappiness (au choix)

Afficher la configuration du fichier swappiness:
[code lg="bash"]
cat /proc/sys/vm/swappiness
60
[/code]

60 signifie que à partir de 60% de mémoire utilisée, le système va avoir tendance à swapper.
Et j''insiste sur le terme "va avoir tendance".

60 est la valeur par défaut lorsque un système Linux est installé. Ceci explique pourquoi au vu de ma faible quantité en mémoire, j''ai déjà un peu de pages en swap.
Pour des besoins spécifiques, il est possible de changer cette valeur.
Red Hat recommande de passer à 10 pour de la base de donnée (cas chez mon client actuel)


Modifier le swappiness: (volatile). Cette commande nécessite d''être root
[code lg="bash"]
echo 10 > /proc/sys/vm/swappiness
[/code]

Modifier la swappiness: (persistant). Cette commande nécessite d''être root
[code lg="bash"]
echo "vm.swappiness = 10" >> /etc/sysctl.conf
[/code]

Ici, le système aura tendance à swapper quand la mémoire sera à 90% d''utilisée

Lancer ensuite les commandes suivantes qui vont désactiver le swap et le relancer avec les nouveaux réglages:
[code lg="bash"]
swapoff -a
swapon -a
[/code]

-a : all : tous les espaces de swap qui seraient présents (swapon -s)


[h2]Suivre la mise en swap [/h2]
Nous allons provoquer volontairement une mise en swap pour cette partie.

On génère un fichier suffisamment volumineux:
[code lg="bash"]
dd if=/dev/zero of=test.txt bs=50000 count=50000
[/code]

if= : ce que je prends en entrée, ici des zéros, contenu sur un pseudo périphérique du système, qui ne contient que des zeros
of= : ce que je vais générer en sortie
bs= : jusqu''à N octets
count = : nombre d''éléments que j''ai pris en entrée donc ici le nombre de zéros, afin de les mettre dans mes octets

puis on l''ouvre avec un éditeur :
[code lg="bash"]
vi test.txt
[/code]

Pour suivre les mouvements au niveau de la mémoire, on peut utiliser la commande vmstat (Virtual Memory Statistics)
[code lg="bash"]
vmstat -w 1 6
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
 r  b         swpd         free         buff        cache   si   so    bi    bo   in   cs  us  sy  id  wa  st
 2  1        26624        92504         1144        17892    4   25    37   216  399   65   0   0  99   0   0
 0  1        56576         7084          120        13252 1440 30080  4252 30080 1277  977   1  13   4  83   0
 0  1        62360         5968          120        14456 7804 5776  9312  5776  658  689   0   6   0  94   0
 0  2        75728         7944          120        14380  672 13416   672 13416  546  154   0   4   0  96   0
 0  3        46336         8516          116        13324 3908 19708  8560 19708 1209  801   3  14   9  75   0
 0  2        56832         7152          116        16836 3144 10692  7124 10692  668  527   0   4   0  96   0
[/code]

- w : pour un affichage plus clair (Mais oui, c''est clair !)
1 : actualisation toutes les 1 secondes
6 : on souhaite afficher 6 valeurs
Sans paramètre, une seule valeur sera affichée

C''est la colonne swap qui va nous intéresser.
Point d''attention, on doit se placer par rapport à la mémoire physique donc :
si : « Swap In » : les pages déchargées du SWAP vers la RAM par seconde
so : « Swap Out » : les pages déchargées de la RAM vers la SWAP par seconde

Mon action d''ouvrir le fichier est donc en train de provoquer de la mise en swap. J''ai saturé la mémoire
Les pages mémoire sous la colonne so sont importantes.

Les autres paramètres ne seront pas détaillés ici.

[code lg="bash"]
free -m
              total        used        free      shared  buff/cache   available
Mem:            483         457           8           0          18          14
Swap:           507         157         350
[/code]

La commande top peut être aussi utilisée
[code lg="bash"]
top
[/code]


[h2]Identifier le /les processus qui swapent [/h2]
J''ai clairement indiqué ici que c''était mon vi qui causait la mise en swap mais si on ne sait pas, comment l''identifier ?

La mise en swap est faite parce que la mémoire est saturée donc il faut identifier les top processus mémoire:
[code lg="bash"]
ps -eo pmem,pid,cmd | tail -n +2 | sort -nr | head
82.8   670 vi test.txt
 0.5   687 ps -eo pmem,pid,cmd
 0.4   643 -bash
 0.1   690 head
 0.1   689 sort -nr
 0.1   688 tail -n +2
 0.1   635 sshd: kage@pts/1
 0.0     9 [ksoftirqd/0]
 0.0     8 [mm_percpu_wq]
 0.0     6 [kworker/0:0H-kblockd]
[/code]

-e : tous les processus
-o : pour faire une sortie de colonnes spécifiques qui sont sont ici le pourcentage de mémoire consommée, le pid, et la commande
tail -n + 2 : va nous permettre d''exclure les titres des colonnes du résultat sinon cela se retrouve dans le tri
sort -nr : tri décroissant par le nombre
head : on affiche seulement le top 10 des valeurs

83% de la mémoire est prise par le processus dont le pid est 670, qui est mon vi

[h2]Ajouter un swap [/h2]
Mon swap est maintenant en train de se remplir a vue de nez. Si je ne fais rien, mon swap va se retrouver saturé.
Je peux ajouter un espace de swap supplémentaire
Dans mon cas, j''utilise LVM.

Voici quelques infos sur mon LVM:
Informations sur mon VG : un seul VG appelé rootvg dont l''espace libre est de 8Go
[code lg="bash"]
sudo vgs
VG     #PV #LV #SN Attr   VSize  VFree
  rootvg   2   5   0 wz--n- 15,75g <8,04g
[/code]

Informations sur mes LVs : 5 LVs dont 1 espace de swap
[code lg="bash"]
sudo lvs
  LV     VG     Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lvhome rootvg -wi-ao----   4,07g
  lvroot rootvg -wi-ao----  <1,95g
  lvswap rootvg -wi-ao---- 508,00m
  lvtmp  rootvg -wi-ao---- 248,00m
  lvvar  rootvg -wi-ao---- 980,00m
[/code]

Afin de donner de l''air, j''ajoute un nouvel espace de swap. Chez mon client actuel, on considère que c''est à partir de 70% de remplissage du swap que ça devient critique. On va donc anticiper

On ajoute un nouveau LV appelé lvtmpswap:
[code lg="bash"]
sudo lvcreate rootvg -n lvtmpswap -L 512M
[/code]

-n : nom du LV à créer
-L :  taille du LV

On formate cet espace en espace swap avec la commande mkswap:
[code lg="bash"]
sudo mkswap /dev/rootvg/lvtmpswap
[/code]

On active cet espace swap avec la commande swapon:
[code lg="bash"]
sudo swapon /dev/rootvg/lvtmpswap
[/code]

Comme c''est un espace swap temporaire, dans le but d''éviter le fameux "cannot fork", je n''écris rien dans la fstab. Je ne souhaite pas que ce swap soit persistant.

On peut vérifier l''arrivée du nouvel espace de swap, qui ici sera la périphérique /dev/dm-5
[code lg="bash"]
swapon -s
Nom de fichier                          Type            Taille  Utilisé Priorité
/dev/dm-1                               partition       520188  166912  -2
/dev/dm-5                               partition       524284  0       -3
[/code]


[h2]Retirer un swap [/h2]
Une fois la situation revenue à la normale, on peut supprimer le LV

Désactivation de l''espace swap
[code lg="bash"]
sudo swapoff /dev/rootvg/lvtmpswap
[/code]

Suppression du LV:
[code lg="bash"]
sudo lvremove /dev/rootvg/lvtmpswap
[/code]

Vérification:
[code lg="bash"]
swapon -s
Nom de fichier                          Type            Taille  Utilisé Priorité
/dev/dm-1                               partition       520188  25184   -2
[/code]

Les pages restantes dans le swap, vont progressivement se vider. On peut vérifier à nouveau les mouvements au niveau du swap avec la commande vmstat.

On pourrait aussi forcer un vidage en le désactivant également. Il faut idéalement désactiver un swap quand il y peu / plus de mouvement au niveau du SWAP car il y a un risque, en supprimant un espace de swap contenant encore des pages mémoires en cours d''utilisation, d''impacter les performances sur le service rendu.



', 'Gestion du SWAP sous Linux', '2020-08-05 16:27:37 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('d8cac1f1-80ea-41ed-9d45-1593dcf3ea6c', 'POST3RJ6BO0RSM', 'Réparer le boot windows', '[h1]Problème[/h1]
Windows 10 de boot plus, il affiche l''erreur suivante : "IO1 Initialization failed" comme affiché sur l''image de ce post.
[h2]Causes possibles de l''erreur[/h2]
 - Mise à jour corrompue de Windows.
 - Arrêt de la machine lors d''une mise à jour de Windows.
 - Bidouillage de partitions (redimentionnement ou déplacement par exemple)
[h2]Explication[/h2]
Windows ne boot plus car un ou plusieurs fichiers de la partition EFI est corrompu/modifié de manière incorrect.
Je soupçonne le fichier "<LECTEUR>:/EFI/Microsoft/Boot/BCD" d''être la cause précise de l''erreur.
[h1]Résolution[/h1]
Il va falloir supprimer la partition de boot, puis la recréer et enfin faire une installation BCD.
[h2]Suppression puis création de la partition de EFI[/h2]
Il va falloir utiliser une clef USB d''installation de Windows 10.
 - Branchez la et bootez dessus en mode UEFI et x64.
 - Cliquez sur "Réparer l''ordinateur"
 - Lancez un terminal CMD
Une fois le terminal ouvert, il faut lancer la commande "diskpart".

Vous pouvez lister les disques détectés avec cette commande :
[code lg="bash"]
list disk
[/code]

Sélectionnez le disque sur lequel est présent votre partition EFI actuelle :
[code lg="bash"]
sel disk <diskNumber>
[/code]

Listez les partitions détectées :
[code lg="bash"]
list part
[/code]

Sélectionnez la partition EFI :
[code lg="bash"]
sel part <partNumber>
[/code]

Supprimez la partition :
[code lg="bash"]
delete partition
[/code]

Note : Ajoutez l''argument "override" si la suppression n''a pas réussi à cause de problèmes de droits ou autre.

Créez la partition :
[code lg="bash"]
create partition efi
[/code]

Formatez la partition en "fat32" :
[code lg="bash"]
format quick fs=fat32
[/code]

Ne quittez pas "diskpart", on en aura encore besoin pour le point suivant.
[h2]Installation BCD[/h2]
À ce stade, nous avons recréé la partition EFImais il va falloir installer les fichiers BCD permettant le boot de l''OS.
Pour cela, on va sélectionner le volume correspondant à la partition EFI puis on va procéder à l''installation BCD.

[h3]Sélection du volume[/h3]
Toujours dans la "cmd", dans l''outil "diskpart", listez les volumes détectés :
[code lg="bash"]
list vol
[/code]

Sélectionnez le volume correspondant à la partition EFI, celui-ci devrait mesurer soit ~100Mo soit ~150Mo en fonction de comment il a été créé à la base :
[code lg="bash"]
sel vol <volumeNumber>
[/code]

Affectez une lettre au volume pour pouvoir accéder à son contenu (équivaut à un "mount") :
[code lg="bash"]
assign letter=R:
[/code]

Note : Dans la commande ci-dessus, on affecte la lettre "R" au volume EFI.

Maintenant on peut quitter l''outil "diskpart" :
[code lg="bash"]
exit
[/code]

[h3]Installation BCD[/h3]
Placez vous au bon endroit et faites une copie de l''ancien fichier "BCD", au cas où... :
[code lg="bash"]
cd /d R:|RFI|Microsoft|Boot
ren BCD BCD.old
[/code]

Note : "R" étant la lettre sur laquelle on a monté le volume EFI.

Faites l''installation BCD via la commande suivante :
[code lg="bash"]
bcdboot E:|Windows /l fr-fr /s R: /f UEFI
[/code]

Note : Dans l''exemple ci-dessus, la lettre "E" correspond au volume sur lequel est installé Windows 10. La lettre "R" correspond au volume EFI.

À partir de là, votre système Windows devrait être capable de booter.

[h1]Cas du double boot[/h1]
Dans mon cas, j''ai 2 disques avec une configuration semblable à ce qui suit :
 - Disque n°1 : Contient une partition EFI et une partition Debian qui accueil Grub
 - Disque n°2 : Contient une partition EFI secondaire spécifique à Windows 10, et une partition Windows 10

Après l''installation BCD, cette dernière avait modifié la configuration de mon UEFI afin de changer l''ordre de boot de mes disques. Ce dernier étant configuré pour booter d''abord sur le disque n°1 puis le n°2, l''installation avait passé le disque n°2 en premier pour l''ordre de boot car c''est celui qui accueil la partition EFI de windows que je venais de réinstaller. Pour rétablir de dual-boot avec grub, il suffit de remodifier l''ordre de boot des disques. Aucune autre installation, ni grub ni autre, n''est nécessaire.

[h3]Sources[/h3]
[link href="https://www.easeus.com/partition-master/restore-repair-deleted-efi-boot-partition-in-windows-10-8-7.html" txt="https://www.easeus.com/partition-master/restore-repair-deleted-efi-boot-partition-in-windows-10-8-7.html" /]
[link href="https://www.malekal.com/reparer-demarrage-de-windows-10/#Reparer_le_demarrage_de_Windows_en_EFI_manuellement" txt="https://www.malekal.com/reparer-demarrage-de-windows-10/#Reparer_le_demarrage_de_Windows_en_EFI_manuellement" /]', 'Recréer la partition EFI afin de réparer le démarrage de windows', '2020-03-25 19:01:34 +01:00', 'b541c414-8646-45a6-ab60-c3ab48ef5e93', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '2cad9c28-ab5d-4c8f-b7da-70ff8bc02586'),
('ae9fac9f-c315-474e-b841-c0ec79d1d686', 'POSTXH61E07NNL', 'Connexion TLS avec certificats auto-signés', '[h1]Génération du certificat[/h1]
Ici on va générer un certificat qui va garder l''IP ou le nom de l''hôte qui l''utilisera (via l''argument "-ext") :
[code lg="bash"]
keytool -genkeypair -keyalg RSA -keysize 2048 -alias certificate-alias -dname "CN=entity,OU=entity,O=France,C=FR" -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -validity 3650 -keystore keystore.p12 -deststoretype pkcs12
[/code]

[h1]Création d''un truststore[/h1]
Il faut créer un fichier dans lequel on va importer la partie publique du certificat précédemment généré, pour qu''il soit utilisé par notre application.
[h2]Export de la partie publique du certificat[/h2]
On peut utiliser un navigateur, en affichant le certificat puis en téléchargeant la partie "pem".
Voici un exemple via Firefox :
[img src="/api/images/huYBKw35GUptlH5NRTqBWeADBSLMnh" /]

[h2]Génération du truststore[/h2]
[code lg="bash"]
keytool -import -alias certificate-alias -file certificate-export.pem -keystore truststore.jks
[/code]

Note : Là il faudra renseigner un mot de passe qui servira à déverouiller le truststore par notre applicatif.
[h1]Exploitation du truststore[/h1]
Là on sera côté Java, il faudra déclarer une fonction "@Bean" produisant un "RestTemplateBuilder" qui génèrera des "RestTemplate" pour notre applicatif, et qui utilisera notre truststore.

On aura besoin de la dépendance suivante :
[code lg="markup"]
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
</dependency>
[/code]

Créer une classe de configuration comme ce qui suit :
[code lg="java"]
@Configuration
public class TrustStoreConfiguration {
    private final Resource keyStore;
    private final String keyStorePassword;

    public TrustStoreConfiguration(@Value("${server.ssl.truststore.path}") Resource keyStore,
                                   @Value("${server.ssl.truststore.password}") String keyStorePassword) {
        this.keyStore = keyStore;
        this.keyStorePassword = [REDACTED]
    }

    @Bean
    public RestTemplateBuilder restTemplate() throws Exception {
        SSLContext sslContext = new SSLContextBuilder()
                .loadTrustMaterial(
                        keyStore.getURL(),
                        keyStorePassword.toCharArray()
                ).build();
        SSLConnectionSocketFactory socketFactory =
                new SSLConnectionSocketFactory(sslContext);
        HttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(socketFactory).build();
        HttpComponentsClientHttpRequestFactory factory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplateBuilder().requestFactory(() -> factory);
    }
}
[/code]

Et définissez les properties comme ce qui suit (application.yml) :
[code lg="markup"]
server:
  ssl:
    truststore:
      path: classpath:truststore.jks
      password: [REDACTED]

[/code]

[h3]Sources[/h3]
[link href="https://blog.univalence.io/pkix-path-building-failed-unable-to-find-valid-certification-path-to-requested-target-a-tes-souhaits/" txt="https://blog.univalence.io/pkix-path-building-failed-unable-to-find-valid-certification-path-to-requested-target-a-tes-souhaits/" /]
[link href="https://stackoverflow.com/questions/27724544/specifying-trust-store-information-in-spring-boot-application-properties" txt="https://stackoverflow.com/questions/27724544/specifying-trust-store-information-in-spring-boot-application-properties" /]
[link href="https://raymondhlee.wordpress.com/2016/01/09/setup-spring-resttemplate-to-accept-self-signed-cert/" txt="https://raymondhlee.wordpress.com/2016/01/09/setup-spring-resttemplate-to-accept-self-signed-cert/" /]
[link href="https://stackoverflow.com/questions/50928061/certificate-for-localhost-doesnt-match-any-of-the-subject-alternative-names" txt="https://stackoverflow.com/questions/50928061/certificate-for-localhost-doesnt-match-any-of-the-subject-alternative-names" /]', 'Configurer un RestTemplate pour qu''il communique avec un tier utilisant un certificat auto-signé', '2020-04-24 13:29:01 +01:00', '1759c754-768b-4773-b9fc-e3944af76f8e', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '61f9fbf3-3340-4ea4-9661-04089377bb2e'),
('90056397-3543-4b97-947b-79a70326827f', 'POST516E4OOOPH', 'Gestion des sémaphores sous Linux (Unix)', '[h2]Pourquoi cet article ? [/h2]
Cet article fait suite a un cas rencontré en entreprise où plus aucune connexion SSH ne pouvait s''établir sur deux serveurs suite à une utilisation totale des sémaphores.
Celui-ci va montrer comment les inspecter et en dernier recours les supprimer.

L''exemple ci-dessous est réalisée via une Red Hat Enterprise Linux 7.6 avec un kernel 3.10.0
J''ai constaté des différences de résultat (traduction, nombre maximal de sémaphores) sur une Debian 10 avec kernel 4.19.0

[h2]Les fonctionnalités IPC [/h2]
Le terme IPC, en anglais "Inter Processus Communication" est la "Communication Inter Processus"
Ce mécanisme, dans tout système d''exploitation, sert pour les processus sans lien de parenté, à "discuter" entre eux

Il existe 3 fonctionnalités de communication sous Linux (Unix):
- Les files de messages  : échanges de messages entre les processus

- Les mémoires partagées : Zone mémoire attachée à un processus mais accessible pour d’autres processus.
Lorsqu''un processus modifie la mémoire, tous les autres processus voient la modification

- Les sémaphores : Le processus pour faire ses modifications va utiliser un sémaphore puis le rendre.
Ceci dans le but de protéger des accès concurrents, et éviter ainsi les blocages d''applications (deadlock en anglais)

Nous allons nous concentrer ici sur les sémaphores.

[h2]Consulter les sémaphores [/h2]
Pour manipuler les I.P.C.s, Linux (Unix) propose plusieurs commandes dont : ipcs (inter processus communication show) et ipcrm (inter processus communication remove)
ipcs peut être utilisé par n''importe quel user sans sudo (sauf lors de la commande ipcs -s -i, qui appellle une fonction nécessitant d’être sudo)
ipcrm nécessite d''être sudo

Afficher l''état des fonctions de la communication inter-processus:
[code lg="bash"]
ipcs -u
[/code]

[code lg="bash"]
------ Messages Status --------
allocated queues = 0
used headers = 0
used space = 0 bytes
------ Shared Memory Status --------
segments allocated 1
pages allocated 1
pages resident  1
pages swapped   0
Swap performance: 0 attempts     0 successes
------ Semaphore Status --------
used arrays = 8
allocated semaphores = 136
[/code]

-u : summary
Ici, 136 sémaphores sont alloués via 8 tableaux.

Pour afficher uniquement les sémaphores (pour être plus précis, les tableaux de sémaphores):
[code lg="bash"]
ipcs -s
[/code]

[code lg="bash"]
------ Semaphore Arrays --------
key        semid      owner      perms      nsems
0x0052e2c1 98304      postgres   600        17
0x0052e2c2 131073     postgres   600        17
0x0052e2c3 163842     postgres   600        17
0x0052e2c4 196611     postgres   600        17
0x0052e2c5 229380     postgres   600        17
0x0052e2c6 262149     postgres   600        17
0x0052e2c7 294918     postgres   600        17
0x0052e2c8 327687     postgres   600        17
[/code]

-s : semaphores
Ici, 8 tableaux identifiés par une clé, un sémaphore id et le propriétaire du processus ayant demander le sémaphore.
Comme on peut le deviner, on est ici sur un serveur PostgreSQL

Afficher les limites des sémaphores:
[code lg="bash"]
ipcs -ls
[/code]

[code lg="bash"]
------ Semaphore Limits --------
max number of arrays = 128
max semaphores per array = 250
max semaphores system wide = 32000
max ops per semop call = 32
semaphore max value = 32767
[/code]

-l : limits
Nombre de sémaphores = nombre de sémaphores par tableaux * nombre de tableaux
Nombre de sémaphores = 250 * 128 = 32000
32 est le nombre maximal d''opérations par appel de sémaphore
32767 est la valeur maximal d''un sémaphore

Ces informations sont aussi dispo via les commandes suivantes :
[code lg="bash"]
cat /proc/sys/kernel/sem
systctl -a | grep sem
[/code]

Attention, les variables ne sont pas dans le même ordre.

[h2]Supprimer les sémaphores [/h2]
Supprimer des fonctions IPC:
[code lg="bash"]
ipcrm
[/code]

Supprimer des sémaphores:
[code lg="bash"]
ipcrm -s
[/code]

Dans notre exemple, il n''est pas utile de libérer les sémaphores car ils en restent.
A noter que en pratique, un redémarrage du service associé aux processus permet de purger les sémaphores
Voici néanmoins un exemple de commande pour les supprimer si ils persistent ou si on ne veut pas redémarrer le service.

Supprimer tous les sémaphores pour un owner spécifique:
[code lg="bash"]
ipcs -s | grep postgre | awk ''{print $2}'' | xargs -i sudo ipcrm -s {}
[/code]

On supprime ici tous les sémaphores de l''utilisateur postgre, en ne retenant que les valeurs de la deuxième colonne (semid)
Pour chaque valeur retournée, on applique la commande ipcrm -s via xargs.

xargs - i : replace string sur les {} avec le résultat obtenu dans le pipe précédent

[h2]Afficher le processus lié à un sémaphore [/h2]
[code lg="bash"]
sudo ipcs -s -i 98304
[/code]

-i : semaphore id

[code lg="bash"]
Semaphore Array semid=98304
uid=10021        gid=531         cuid=10021      cgid=531
mode=0600, access_perms=0600
nsems = 17
otime = Wed May 22 11:23:40 2019
ctime = Wed May 22 11:23:40 2019
semnum     value      ncount     zcount     pid
0          1          0          0          22181
1          1          0          0          22181
2          1          0          0          22181
3          1          0          0          22181
4          1          0          0          22181
5          1          0          0          22181
6          1          0          0          22181
7          1          0          0          22181
8          1          0          0          22181
9          1          0          0          22181
10         1          0          0          22181
11         1          0          0          22181
12         1          0          0          22181
13         1          0          0          22181
14         1          0          0          22181
15         1          0          0          22181
16         537        0          0          22181
[/code]

Le processus qui utilise ce sémaphore porte le PID 22181

[h2]Vérifier si des sémaphores ne sont pas libérés [/h2]
On peut vérifier si des sémaphores ne sont pas libérés en vérifiant l''existence de leur processus qui les a crée

[code lg="bash"]
#Pour chaque sémaphore id dans la colonne des semaphoreid
for semid in `ipcs -s | cut -d" " -f 2`;
#On récupère le numéro de processus dans une variable pid
> do pid=`sudo ipcs -s -i $semid | tail -n 2 | head -n 1 | awk ''{print $5}''`;
#On vérifie l''existence de ce processus avec redirection sortie erreur dans sortie standard puis dans /dev/null afin de ne pas générer de mail d''erreur pour le user root, en cas d''erreur
> ps -p $pid 2>&1 >/dev/null;
#Si ce qui est retourné est vrai, on affiche le pid avec la commande correspondante sinon KO
> [ $? -eq 0 ] && echo "$pid OK $(ps --no-headers -p $pid -o command)" ||  echo "$pid KO";
#Fin de la boucle
> done

22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
22181 OK /usr/pgsql-9.6/bin/postmaster -D /var/lib/pgsql/9.6/main/data/data
[/code]


Sources:
http://man7.org/linux/man-pages/man1/ipcs.1.html
http://supertos.free.fr/supertos.php?page=40
https://www.thegeekdiary.com/how-to-change-kernel-semaphore-limits-in-centos-rhel/
https://perso-etis.ensea.fr//~picard/pluxml/data/documents/os/cours_6.pdf
', 'Qu''est-ce que les fonctionnalités IPC ? dont les sémaphores ? Comment les gérer sous Linux (Unix)', '2020-05-27 23:24:42 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('dacdc6ea-635e-4b5b-8b1d-ea8c6426be32', 'POSTL8SVWQ4SHL', 'Gérer un mot de passe LDAP dans KeePassXC', '[h1]Contexte[/h1]
Dans un contexte d''entreprise, chaque salarié a un compte enregistré au près d''un serveur LDAP et tous les outils internes utilisent une authentification en passant par ce serveur LDAP.

Par conséquent, on peut se retrouver avec plusieurs entrées dans KeePassXC avec le même mot de passe, sauf qu''au moment de changer son mot de passe (à cause d''une politique de sécurité : expiration tous les 3 mois), ça devient très pénible de mettre à jour toutes ses entrées dans KeePassXC.

Mais heureusement il existe une fonctionnalité dans l''outil qui permet de faire référence aux données d''une autre entrée (nom d''utilisateur, mot de passe...).

[h1]Mise en place[/h1]
La première étape consiste à mettre en place une entrée qui servira de référence pour toutes les autres. On peut l''appeler "Mot de passe LDAP" par exemple.

Ensuite, on va créer une nouvelle entrée.
Mais dans les champs "Nom d''utilisateur" et "Mot de passe", on ne va pas recopier les identifiant mais utiliser une syntaxe particulière qui permet de faire référence à une autre entrée :

[code lg="bash"]
# Pour le nom d''utilisateur :
{REF:U@I:<UUID>}

# Pour le mot de passe :
{REF:P@I:<UUID>}
[/code]

Note : "<UUID>" correspond à l''identifiant de l''entrée principale ("Mot de passe LDAP" dans notre cas) qui se trouve dans les propriétés de l''entrée :
[img src="/api/images/fF2y87sCb7R4XL43PSVKIGsvHRXLQp" /]

Il reste plus qu''à renseigner le champ "URL" sur toutes les entrées utilisant le mot de passe LDAP afin que l''extension de navigateur puisse remplir automatiquement le mot de passe.

[h3]Sources[/h3]
[link href="https://keepass.info/help/base/fieldrefs.html" txt="https://keepass.info/help/base/fieldrefs.html" /]
[link href="https://keepassxc.org/docs/KeePassXC_UserGuide.html#_reference" txt="https://keepassxc.org/docs/KeePassXC_UserGuide.html#_reference" /]', 'Définir plusieurs sites webs utilisant un même mot de passe (contexte d''entreprise avec un serveur LDAP)', '2023-02-07 10:17:30 +01:00', '9a28d33f-37af-45aa-8be6-88f41dcd14f6', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'f46fb104-4f53-4732-b33b-6a3ef8c2c0a3'),
('890b98d6-468b-4a21-83c7-bb9b2444d4ee', 'POSTGAJJJ9YBIH', 'Réduire la taille d''un PDF', '[h1]Commande[/h1]
[code lg="bash"]
gs -q -dSAFER -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/printer -sOUTPUTFILE=newPDF.pdf -f PDF.pdf
[/code]

Note : Il existe plusieurs valeurs pour le paramètre "PDFSETTINGS", afin de plus ou moins compresser le fichier final, dans l''ordre du plus compressé au moins compressé :
  - /screen
  - /ebook
  - /printer
  - /prepress
  - /default
Attention ! Vérifiez bien la lisibilité du document après convertion, car les formats les plus compressés peuvent nuire à la lisibilité du document.

[h3]Sources[/h3]
[link href="https://www.ludovicfavre.ch/blog/2011/05/reduire-la-taille-dun-fichier-pdf-avec-ghostscript/" txt="https://www.ludovicfavre.ch/blog/2011/05/reduire-la-taille-dun-fichier-pdf-avec-ghostscript/" /]', 'Commande pour réduire la taille d''un PDF sous Linux via ghostscript', '2020-10-11 22:22:07 +01:00', 'b687928c-4b96-454e-be25-8615e6fc5ca5', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('49bcc946-228a-487c-a3b1-6208d68db15a', 'POST8AVOZP182P', 'Lancer des tâches NPM avec VSCode', '[h1]Configuration[/h1]
Dans l''onglet "Run" de VSCode, il faut créer le fichier ".vscode/launch.json" puis y ajouter cette configuration :

[code lg="markup"]
{
    "name": "React app - start",
    "type": "node",
    "request": "launch",
    "cwd": "${workspaceRoot}/pocReact/react-app",
    "runtimeExecutable": "npm",
    "runtimeArgs": [
        "run", "build"
    ],
    "skipFiles": [
        "<node_internals>/**"
    ]
}
[/code]

[h3]Sources[/h3]
[link href="https://stackoverflow.com/questions/34835082/how-to-debug-using-npm-run-scripts-from-vscode"  txt="https://stackoverflow.com/questions/34835082/how-to-debug-using-npm-run-scripts-from-vscode" /]', 'Lancer des tâches NPM avec le debugger VSCode', '2020-10-15 10:06:43 +01:00', '69bf1b33-9cc3-4e97-a27d-2236bb2c2a7f', 'd1d557a6-88b1-4274-994e-f9a9a6097997', 'f46fb104-4f53-4732-b33b-6a3ef8c2c0a3'),
('e65ad55d-3015-4e5f-904f-4db7157849d2', 'POSTZVO0JKS0T2', 'Haute disponibilité sous GNU Linux : Mise en place d''un RAID miroir', '[h2]Composition du serveur[/h2]
Le serveur dispose d''un disque de 8Go /dev/sda avec une partition sda5 sous LVM
[code lg="bash"]
$ lsblk
NAME              MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                 8:0    0    8G  0 disk
├─sda1              8:1    0  243M  0 part /boot
├─sda2              8:2    0    1K  0 part
└─sda5              8:5    0  7,8G  0 part
  ├─rootvg-lvroot 254:0    0    2G  0 lvm  /
  ├─rootvg-lvswap 254:1    0  508M  0 lvm  [SWAP]
  ├─rootvg-lvvar  254:2    0  980M  0 lvm  /var
  ├─rootvg-lvtmp  254:3    0  248M  0 lvm  /tmp
  └─rootvg-lvhome 254:4    0  4,1G  0 lvm  /home
[/code]

[h2]Mise en place du RAID[/h2]
[code lg="bash"]
$ sudo apt-get install mdadm
[/code]

Comme j''utilise VirtualBox, je dois arrêter la VM pour pouvoir ajouter deux disques. Avec VMware, cette action aurait pu être faite à chaud
Si cela avait été le cas, on aurait pu utiliser la commande suivante pour rescanner les bus SCSI sur le système afin de découvrir le nouveau disque sans redémarrer le système
[code lg="bash"]
# for host in /sys/class/scsi_host/*; do echo "- - -" | tee $host/scan; ls /dev/sd* ; done
[/code]

Vérification:
[code lg="bash"]
$ lsblk
NAME              MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                 8:0    0    8G  0 disk
├─sda1              8:1    0  243M  0 part /boot
├─sda2              8:2    0    1K  0 part
└─sda5              8:5    0  7,8G  0 part
  ├─rootvg-lvroot 253:0    0    2G  0 lvm  /
  ├─rootvg-lvswap 253:1    0  508M  0 lvm  [SWAP]
  ├─rootvg-lvvar  253:2    0  980M  0 lvm  /var
  ├─rootvg-lvtmp  253:3    0  248M  0 lvm  /tmp
  └─rootvg-lvhome 253:4    0  4,1G  0 lvm  /home
sdb                 8:16   0    8G  0 disk
sdc                 8:32   0    8G  0 disk
[/code]

Création du raid avec les deux disques ajoutés:
[code lg="bash"]
sudo mdadm --create /dev/md1 --level=raid1 --raid-devices=2  /dev/sdb /dev/sdc
[/code]

/dev/md1 : nom du raid ==> doit respecter ce nommage sinon message d''erreur
--level=raid1 : définition d''un raid en mirroring
--raid-devices=2 : on utilise deux disques

On peut afficher les infos sur le RAID avec la commande suivante:
[code lg="bash"]
$ sudo mdadm --detail /dev/md1
/dev/md1:
           Version : 1.2
     Creation Time : Wed Oct  7 13:33:03 2020
        Raid Level : raid1
        Array Size : 8379392 (7.99 GiB 8.58 GB)
     Used Dev Size : 8379392 (7.99 GiB 8.58 GB)
      Raid Devices : 2
     Total Devices : 2
       Persistence : Superblock is persistent

       Update Time : Wed Oct  7 13:33:45 2020
             State : clean
    Active Devices : 2
   Working Devices : 2
    Failed Devices : 0
     Spare Devices : 0

Consistency Policy : resync

              Name : debianclient:1  (local to host debianclient)
              UUID : f301b219:25a1f741:4c08ebf9:95983fa2
            Events : 17

    Number   Major   Minor   RaidDevice State
       0       8       16        0      active sync   /dev/sdb
       1       8       32        1      active sync   /dev/sdc
[/code]

Les deux disques sont bien à l''état actif.

ou en moins verbeux:
[code lg="bash"]
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md1 : active raid1 sdc[1] sdb[0]
      8379392 blocks super 1.2 [2/2] [UU]

unused devices: <none>
[/code]

Pour que le nommage du RAID soit persistent, il faut passer mettre à jour le initramfs, auquel cas, lors du prochain reboot du serveur, celui-ci sera nommé /dev/md127
https://openclassrooms.com/forum/sujet/raid-md0-devient-md127
[code lg="bash"]
$ sudo update-initramfs -u -k all
[/code]

-u : update
-k : kernel
all : pour tous les kernels



[h2]Intégration à LVM[/h2]
Avec ce nouveau device, je vais créer un physical volume (PV)
[code lg="bash"]
sudo pvcreate /dev/md1
[/code]

Vérification:
[code lg="bash"]
$ sudo pvs
  PV         VG     Fmt  Attr PSize  PFree
  /dev/md1          lvm2 ---   7,99g  7,99g
  /dev/sda5  rootvg lvm2 a--  <7,76g 40,00m
[/code]

[code lg="bash"]
$ sudo pvdisplay /dev/md1
"/dev/md1" is a new physical volume of "7,99 GiB"
--- NEW Physical volume ---
PV Name               /dev/md1
VG Name
PV Size               7,99 GiB
Allocatable           NO
PE Size               0
Total PE              0
Free PE               0
Allocated PE          0
PV UUID               Oe1VGT-AWh3-6ljp-ivkD-dbbZ-G2ou-dWrSY7
[/code]

Création d''un nouveau VG qui contiendra mes datas applicatives via l''intégration de ce PV:
[code lg="bash"]
$ sudo vgcreate appsvg /dev/md1
Volume group "appsvg" successfully created

$ sudo vgs
  VG     #PV #LV #SN Attr   VSize  VFree
  appsvg   1   0   0 wz--n- <7,99g <7,99g
  rootvg   1   5   0 wz--n- <7,76g 40,00m
[/code]

Création d''un LV dans ce VG: celui-ci servira pour mon tomcat
[code lg="bash"]
$ sudo lvcreate appsvg -n lvtomcat -L 2G
[/code]

-n : nom du LV
-L : Taille du LV

Vérification:
[code lg="bash"]
$ sudo lvs
  LV       VG     Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lvtomcat appsvg -wi-a-----   2,00g
  lvhome   rootvg -wi-ao----   4,07g
  lvroot   rootvg -wi-ao----  <1,95g
  lvswap   rootvg -wi-ao---- 508,00m
  lvtmp    rootvg -wi-ao---- 248,00m
  lvvar    rootvg -wi-ao---- 980,00m
[/code]

Activation du VG au démarrage:
[code lg="bash"]
$ sudo vgchange -ay appsvg
[/code]

Création de l''entrée dans le fichier fstab: J''inscris une nouvelle ligne
[code lg="bash"]
$ sudo vi /etc/fstab
/dev/mapper/appsvg-lvtomcat /produit/tomcat ext4 defaults 0 2
[/code]

On crée un système de fichier dans ce LV:
[code lg="bash"]
$ sudo mkfs.ext4 /dev/mapper/appsvg-lvtomcat
[/code]

Puis on fait le montage:
[code lg="bash"]
$ sudo mount -a
[/code]

-a : montage de toutes les entrées de /etc/fstab. Si le montage est déjà fait, celui-ci n''est pas remonté

Résultat avec lsblk:
[code lg="bash"]
$ lsblk
NAME                MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                   8:0    0    8G  0 disk
├─sda1                8:1    0  243M  0 part  /boot
├─sda2                8:2    0    1K  0 part
└─sda5                8:5    0  7,8G  0 part
  ├─rootvg-lvroot   253:0    0    2G  0 lvm   /
  ├─rootvg-lvswap   253:1    0  508M  0 lvm   [SWAP]
  ├─rootvg-lvvar    253:2    0  980M  0 lvm   /var
  ├─rootvg-lvtmp    253:3    0  248M  0 lvm   /tmp
  └─rootvg-lvhome   253:4    0  4,1G  0 lvm   /home
sdb                   8:16   0    8G  0 disk
└─md1                 9:1    0    8G  0 raid1
  └─appsvg-lvtomcat 253:5    0    2G  0 lvm   /produit/tomcat
sdc                   8:32   0    8G  0 disk
└─md1                 9:1    0    8G  0 raid1
  └─appsvg-lvtomcat 253:5    0    2G  0 lvm   /produit/tomcat
[/code]

[h2]Test endommagement du RAID[/h2]
Pour le test, je crée un répertoire apprenant à l''utilisateur tomcat. Peu importe le nom, c''est pour le test.
[code lg="bash"]
$ ls -l /produit/tomcat/
total 20
drwxr-xr-x 2 tomcat tomcat  4096 oct.   8 16:08 codiki
drwx------ 2 tomcat tomcat 16384 oct.   7 13:59 lost+found
[/code]

Afin de simuler une panne côté disque, nous allons retirer le disque /dev/sdc côté système:
[code lg="bash"]
# echo 1 > /sys/block/sdc/device/delete
[/code]

Vérification après de l''état du RAID:
[code lg="bash"]
$ sudo mdadm --detail /dev/md1
/dev/md1:
           Version : 1.2
     Creation Time : Wed Oct  7 13:33:03 2020
        Raid Level : raid1
        Array Size : 8379392 (7.99 GiB 8.58 GB)
     Used Dev Size : 8379392 (7.99 GiB 8.58 GB)
      Raid Devices : 2
     Total Devices : 1
       Persistence : Superblock is persistent

       Update Time : Thu Oct  8 17:29:58 2020
             State : clean, degraded
    Active Devices : 1
   Working Devices : 1
    Failed Devices : 0
     Spare Devices : 0

Consistency Policy : resync

              Name : debianclient:1  (local to host debianclient)
              UUID : f301b219:25a1f741:4c08ebf9:95983fa2
            Events : 20

    Number   Major   Minor   RaidDevice State
       0       8       16        0      active sync   /dev/sdb
       -       0        0        1      removed
[/code]

Si je me déplace dans mon fs tomcat, celui-ci est bien toujours là

[h2]Remplacement du disque défaillant[/h2]
Redécouverte du disque en scannant les bus SCSI: celui-ci n''a pas été retiré de Virtualbox
[code lg="bash"]
# for host in /sys/class/scsi_host/*; do echo "- - -" | tee $host/scan; ls /dev/sd* ; done
[/code]

Ajout du disque sur un raid déjà existant:
[code lg="bash"]
sudo mdadm --manage /dev/md1  --add /dev/sdc
[/code]

Vérification de la reprise du mirroring:
[code lg="bash"]
$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md1 : active raid1 sdc[2] sdb[0]
      8379392 blocks super 1.2 [2/1] [U_]
      [===============>.....]  recovery = 76.3% (6401536/8379392) finish=0.1min speed=206501K/sec

$ cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
md1 : active raid1 sdc[2] sdb[0]
      8379392 blocks super 1.2 [2/2] [UU]
[/code]

Enfin, la commande pour arrêter le RAID:
[code lg="bash"]
$ sudo mdadm --stop /dev/md1
[/code]

ainsi que la commande pour monter tous les RAID qui seraient présents:
[code lg="bash"]
$ sudo mdadm --assemble --scan
[/code]', ' Mise en place d''un RAID miroir sous Debian 10', '2020-10-20 13:18:41 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('938a6b93-58fd-49ca-90d2-fc94dc47971b', 'POSTA8MZCJT5RO', 'Installer PgAdmin4 sur un serveur', '[h1]Installation[/h1]
Il suffit de suivre les instructions décrites à cet endroit :
[link href="https://www.pgadmin.org/download/pgadmin-4-apt/" txt="https://www.pgadmin.org/download/pgadmin-4-apt/" /]

Soit :
[code lg="bash"]
#
# Setup the repository
#

# Install the public key for the repository (if not done previously):
curl https://www.pgadmin.org/static/packages_pgadmin_org.pub | sudo apt-key add

# Create the repository configuration file:
sudo sh -c ''echo "deb https://ftp.postgresql.org/pub/pgadmin/pgadmin4/apt/$(lsb_release -cs) pgadmin4 main" > /etc/apt/sources.list.d/pgadmin4.list && apt update''

#
# Install pgAdmin
#

# Install for web mode only:
sudo apt install pgadmin4-web
[/code]


[h1]Configuration[/h1]
[h2]PgAdmin 4[/h2]
On peut générer la configuration apache pour qu''il serve l''application PgAdmin4, en tappant la commande suivante :
[code lg="bash"]
sudo /usr/pgadmin4/bin/setup-web.sh
[/code]

Un mode interactif s''activera dans votre terminal. Il suffira de choisir le mode "Apache".

Ce script va générer le fichier suivant :
[code lg="bash"]
/etc/apache2/conf-available/pgadmin4.conf
[/code]

Par défaut, PgAdmin4 sera servi sur le port "80" de la machine, et au endpoint suivant : "/pgadmin4".
Afin de faire un ReverseProxy avec apache, pour activer le protocole https, il va falloir supprimer le endpoint pour fournir l''application à la racine de l''url ("/"), et il va falloir modifier le port d''exposition en utilisant un virtual-host.

[h2]Apache[/h2]
[h3]Ajout d''un port d''écoute[/h3]
Pour modifier le port d''exposition de PgAdmin4, il va falloir rajouter un port d''écoute dans la configuration d''apache.
Pour se faire, il faut modifier le fichier suivant :
[code lg="bash"]
/etc/apache2/ports.conf
[/code]

Et il faut ajouter la conf suivante :
[code lg="bash"]
Listen 80
...
# Ajout du nouveau port d''écoute :
Listen 8080
[/code]

[h3]L''exposition de PgAdmin[/h3]
Une fois le port d''écoute ajouté, il faut modifier le fichier de conf apache qui permet d''exposer PgAdmin.
Il s''agit du fichier suivant :
[code lg="bash"]
/etc/apache2/conf-available/pgadmin4.conf
[/code]

Il faut maintenant lui ajouter un virtual-host et supprimer l''endpoint :
[code lg="bash"]
# Ajout du virtual host ici
<VirtualHost *:8080>
	WSGIDaemonProcess pgadmin processes=1 threads=25 python-home=/usr/pgadmin4/venv
	# Ici il faut supprimer "/pgadmin4" pour le remplacer par "/"
	WSGIScriptAlias / /usr/pgadmin4/web/pgAdmin4.wsgi

	<Directory /usr/pgadmin4/web/>
	    WSGIProcessGroup pgadmin
	    WSGIApplicationGroup %{GLOBAL}
	    Require all granted
	</Directory>
</VirtualHost>
[/code]

Il suffit de recharger la configuration d''apache et vous pouvez tester si vous arrivez à accéder à PgAdmin via cette url : http://<ip-du-serveur>:8080/

[h3]Mise en place du protocole https[/h3]
Il suffit de suivre les instructions décrites dans cet article :
[link href="https://codiki.org/posts/POST15UG2MIB1E" txt="https://codiki.org/posts/POST15UG2MIB1E" /]

[h1]Sources[/h1]
[link href="https://www.yobihat.com/install-pgadmin4-v3-2-in-server-mode-on-ubuntu-16-18-with-https-on-apache2/" txt="https://www.yobihat.com/install-pgadmin4-v3-2-in-server-mode-on-ubuntu-16-18-with-https-on-apache2/" /]
[link href="https://codiki.org/posts/POST15UG2MIB1E" txt="https://codiki.org/posts/POST15UG2MIB1E" /]
[link href="https://www.groovypost.com/howto/apache/configure-apache-web-site-to-use-multiple-ports/" txt="https://www.groovypost.com/howto/apache/configure-apache-web-site-to-use-multiple-ports/" /]', 'Installer PgAdmin4 en mode web et activer le protocole https avec apache', '2020-10-25 12:11:34 +01:00', 'a6f97612-b754-4291-8882-07f37d17bc91', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('2b097b40-ea21-4fed-b2a1-dad7c4c81c9b', 'POSTEY2JZQ6CQ8', 'Renommer un VG contenant root (Debian 10)', '[h2]Introduction [/h2]
Renommer un VG contenant la racine (root) implique de nombreuses modifications au risque de plus pouvoir booter lors du prochain démarrage
Présentation de la configuration LVM du serveur (installée lors de l''installation de Debian)

Les PVs : un seul Physical Volume
[code lg="bash"]
sudo pvs
  PV         VG                  Fmt  Attr PSize  PFree
  /dev/sda5  debianserverbase-vg lvm2 a--  <7,76g 40,00m
[/code]

Les VGs : un seul Volume Group
[code lg="bash"]
sudo vgs
  VG                  #PV #LV #SN Attr   VSize  VFree
  debianserverbase-vg   1   5   0 wz--n- <7,76g 40,00m
[/code]

Les LVs : 5 Logical Volume
[code lg="bash"]
sudo lvs
  LV     VG                  Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  home   debianserverbase-vg -wi-ao----   4,07g
  root   debianserverbase-vg -wi-ao----  <1,95g
  swap_1 debianserverbase-vg -wi-ao---- 508,00m
  tmp    debianserverbase-vg -wi-ao---- 248,00m
  var    debianserverbase-vg -wi-ao---- 980,00m
[/code]

Nous allons renommer le VG debianserverbase-vg (nom donnée par défaut lors de installation de Debian) en rootvg

[h2]Déroulé des actions [/h2]
1. Renommage du VG
[code lg="bash"]
sudo vgrename debianserverbase-vg rootvg
  Volume group "debianserverbase-vg" successfully renamed to "rootvg"
[/code]

Vérification:
[code lg="bash"]
sudo vgs
  VG     #PV #LV #SN Attr   VSize  VFree
  rootvg   1   5   0 wz--n- <7,76g 40,00m
[/code]

2. Activation du VG au démarrage
[code lg="bash"]
sudo vgchange -ay
  5 logical volume(s) in volume group "rootvg" now active
[/code]

-a : activate
y : yes

3. Renommage des occurrences dans le fichier fstab
2 possibilités, le faire à la main avec un éditeur de texte ou utiliser la commande sed. C''est cette deuxième solution que l''on va retenir

[code lg="bash"]
sudo sed -i ''s/debianserverbase--vg/rootvg/g'' /etc/fstab
[/code]

-i : mode édition. Sinon, par défaut, ne fait rien
 ''s/chaine de caractère à substituer/nouveaux caractères/g''

4. Mise à jour du fichier grub.cfg
[code lg="bash"]
cat /boot/grub/grub.cfg | grep vg
    insmod vga
        linux   /vmlinuz-4.19.0-8-amd64 root=/dev/mapper/debianserverbase--vg-root ro  quiet
                linux   /vmlinuz-4.19.0-8-amd64 root=/dev/mapper/debianserverbase--vg-root ro  quiet
                linux   /vmlinuz-4.19.0-8-amd64 root=/dev/mapper/debianserverbase--vg-root ro single
                linux   /vmlinuz-4.19.0-5-amd64 root=/dev/mapper/debianserverbase--vg-root ro  quiet
                linux   /vmlinuz-4.19.0-5-amd64 root=/dev/mapper/debianserverbase--vg-root ro single
[/code]

[code lg="bash"]
sudo grub-update
/usr/sbin/grub-probe : erreur : impossible d''obtenir le chemin canonique de « /dev/mapper/debianserverbase--vg-root »
[/code]

==> idem avec grub-mkconfig

On va donc modifier le fichier en direct avec sed, bien que l''on n''est pas censé le faire...quand je trouverai une solution propre, je mettrai à jour l''article

Renommage des occurrences dans le fichier:
[code lg="bash"]
sed -i ''s/debianserverbase--vg/rootvg/g'' /boot/grub/grub.cfg
[/code]

5. Modification du fichier resume de initramfs
[code lg="bash"]
sudo vi /etc/initramfs-tools/conf.d/resume
RESUME=/dev/mapper/debianserverbase-vg-swap_1
[/code]

en
[code lg="bash"]
RESUME=/dev/mapper/rootvg-swap_1
[/code]

==> si oubli de modification de ce fichier et en cas de reboot, le message d''erreur suivant apparaîtra bloquant le démarrage du serveur :
no matching swap device is available

6.  Mise à jour du initramfs pour tous les kernels
[code lg="bash"]
sudo update-initramfs -u -k all
[/code]

-u : update
-k : kernel

Enfin, on désactive la swap sinon, le serveur ne va pas pourvoir s''arrêter avec un message d''erreur :
no matching swap device is available
Certainement car il y a toujours des traces de l’ancienne conf en mémoire
[code lg="bash"]
sudo swapon -s
Nom de fichier                          Type            Taille  Utilisé Priorité
/dev/dm-1                               partition       520188  268     -2
[/code]

[code lg="bash"]
sudo swapoff /dev/dm-1
[/code]

Vérification finale : arrêt / démarrage du serveur ne doit pas retourner d''erreur', 'Renommage d''un VG contenant root. Plusieurs précautions à prendre', '2020-08-05 16:26:18 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('d26325fb-a595-4970-96c6-19f1cf1ee759', 'POSTV3YYP7E29G', 'Tester la production de logs', '[h1]Introduction[/h1]
Vu que les loggers sont statiques, il est impossible de les mocker "normalement".

L''idée va être d''exploiter l''API de logging afin d''ajouter un appender, le temps des tests, afin qu''il récupère et qu''il stocke tous les messages produits, pour ensuite les contrôler.

[h1]LogCapturer[/h1]

[code lg="java"]
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.stream.Collectors;

import static org.slf4j.Logger.ROOT_LOGGER_NAME;

public class LogCapturer {
    /** Singleton. */
    private static LogCapturer logCapturer;

    /**
     * Returns the {@link LogCapturer}.
     */
    public static LogCapturer get() {
        if (logCapturer == null) {
            logCapturer = new LogCapturer();
        }
        return logCapturer;
    }

    public static void initialize() {
        logCapturer.init();
    }

    public static void reset() {
        logCapturer.tearDown();
    }

    /**
     * List appender to store captured logs.
     */
    private final ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
    /**
     * Root logger.
     */
    private final Logger logger = (Logger) LoggerFactory.getLogger(ROOT_LOGGER_NAME);

    /**
     * Initialize log capturer by attaching it a list appender.
     */
    private void init() {
        logger.addAppender(listAppender);
        listAppender.start();
    }

    /**
     * Tears down log capturer by detaching it its list appender and clearing it.
     */
    private void tearDown() {
        listAppender.stop();
        listAppender.list.clear();
        logger.detachAppender(listAppender);
    }

    /**
     * Retrieves all captured logs.
     */
    public List<LoggingEvent> getLogs() {
        return listAppender.list.stream()
                .map(event -> new LoggingEvent(event.getLevel(), event.getFormattedMessage()))
                .collect(Collectors.toList());
    }

    /**
     * Logging event that represents a log.
     */
    @NoArgsConstructor
    @AllArgsConstructor
    @Getter
    @Setter
    public static class LoggingEvent {
        private Level level;
        private String message;
    }
}

[/code]

Cette classe, "prête à l''emploi" via un copier-coller, expose un objet permettant de stocker les logs générés.

Ensuite, il faut définir une extension JUnit5 afin qu''elle initialise le LogCapturer avant chaque test, et qu''elle vide la liste de message capturés et retire l''appender du logger ROOT après chaque test.

[h1]L''extension JUnit 5[/h1]

[code lg="java"]
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

/**
 * Extension that initialize and clear the {@link LogCapturer} before and after each unit test.
 */
public class LoggingExtension implements BeforeEachCallback, AfterEachCallback {
    @Override
    public void beforeEach(ExtensionContext context) throws Exception {
        LogCapturer.initialize();
    }

    @Override
    public void afterEach(ExtensionContext context) {
        LogCapturer.reset();
    }
}

[/code]

Cette extension implémente les interfaces qui permettent à JUnit d''exécuter un traitement avant et après chaque test.

[h2]L''assertor[/h2]
Voici un assertor basé sur AssertJ permettant d''effectuer les assertions de logging sur notre LogCapturer :

[code lg="java"]

import ch.qos.logback.classic.Level;
import org.codiki.demo.extension.LogCapturer;
import org.assertj.core.api.AbstractObjectAssert;

public class LoggingAssert extends AbstractObjectAssert<LoggingAssert, LogCapturer> {
    public LoggingAssert(LogCapturer logCapturer) {
        super(logCapturer, LoggingAssert.class);
    }

    /**
     * Asserts that the logger is called to log {@code expectedMessage} at level {@code expectedLevel}.
     */
    public LoggingAssert captured(Level expectedLevel, String expectedMessage) {
        isNotNull();

        if (noLogMatches(expectedLevel, expectedMessage)) {
            failWithMessage("An expected logging event is missing at level <%s> with following message <%s>",
                    expectedLevel.levelStr,
                    expectedMessage);
        }

        return this;
    }

    private boolean noLogMatches(Level expectedLevel, String expectedMessage) {
        return actual.getLogs().stream()
                .noneMatch(log -> expectedLevel.equals(log.getLevel()) && expectedMessage.equals(log.getMessage()));
    }
}

[/code]

[h1]Exemple de test[/h1]

[code lg="java"]
@ExtendWith({
        LoggingExtension.class
})
class ServiceTest {
    /** Tested service. */
    private Service service;

    private final LogCapturer logCapturer = LogCapturer.get();

    @BeforeEach
    void setUp() {
        service = new Service();
    }

    @Test
    void should_log_a_message() {
        // when
        service.doSomething();

        // then
        assertThat(logCapturer).captured(INFO, "A log message is generated.");
    }
}
[/code]


[h3]Sources[/h3]
Utilisation du contexte spring dans une extension JUnit5 :
[link href="https://stackoverflow.com/questions/56904620/junit-5-inject-spring-components-to-extension-beforeallcallback-afterallcall" txt="https://stackoverflow.com/questions/56904620/junit-5-inject-spring-components-to-extension-beforeallcallback-afterallcall" /]

Convertion d''une Rule JUnit4 en Extension JUnit 5 pour tester les logs :
[link href="https://stackoverflow.com/questions/42766017/how-to-test-logging-in-junit5" txt="https://stackoverflow.com/questions/42766017/how-to-test-logging-in-junit5" /]

Exemple de projet mettant en place le LogCapturer :
[link href="https://github.com/netmikey/logunit" txt="https://github.com/netmikey/logunit" /]', 'Comment tester que l''application génère des logs avec JUnit 5 et les extensions', '2021-02-26 16:48:15 +01:00', '2ce8a032-5e4d-4921-a589-ee51b3c58437', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '61f9fbf3-3340-4ea4-9661-04089377bb2e'),
('039039a8-f30f-4169-bed8-bd5f80ae86e6', 'POST80WB9CD4GL', 'Gestion du SWAP : Cannot allocate memory', 'Il se peut que la création d''un espace de swap échoue avec un message d''erreur "Cannot allocate memory"

Création du LV qui va contenir notre swap:
[code lg="bash"]
sudo lvcreate rootvg -n lvswap2 -L 8G
Logical volume "lvswap2" created.
[/code]

-n : nom du logical volume
-L : Taille du logical volume

Formatage de ce LV en espace de swap:
[code lg="bash"]
sudo mkswap /dev/rootvg/lvswap2
Setting up swapspace version 1, size = 8388604 KiB
no label, UUID=691d4e9b-31d5-49af-b8d3-cda97142744d
[/code]

Activation de l''espace de SWAP: on obtient une erreur "Cannot allocate memory"
[code lg="bash"]
sudo swapon -v /dev/rootvg/lvswap2
swapon /dev/rootvg/lvswap2
swapon: /dev/mapper/rootvg-lvswap2: found swap signature: version 1, page-size 4, same byte order
swapon: /dev/mapper/rootvg-lvswap2: pagesize=4096, swapsize=8589934592, devsize=8589934592
swapon: /dev/rootvg/lvswap2: swapon failed: Cannot allocate memory
[/code]

-v : verbose

Pour info, le serveur dispose de 60 Go de mémoire et de 8Go de Swap
[code lg="bash"]
free -m
              total        used        free      shared  buff/cache   available
Mem:          60536       26111        2972          36       31453       33343
Swap:          8191        6096        2095
[/code]

Vérification dans les logs de l''event "page allocation failure":
[code lg="bash"]
grep "page allocation failure" /var/log/messages
Aug 17 07:50:33 debianserver kernel: swapon: page allocation failure: order:4, mode:0x10c0d0
Aug 17 08:03:02 debianserver kernel: swapon: page allocation failure: order:4, mode:0x10c0d0
Aug 20 10:10:53 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:54 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:54 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:54 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:54 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:55 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:55 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:55 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:55 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:56 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:59 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:59 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
Aug 20 10:10:59 debianserver kernel: kworker/u256:5: page allocation failure: order:9, mode:0x84d0
[/code]

En fait, le problème vient du fait que lors de la création d''un espace de swap, Linux doit procéder à des opérations d''allocations mémoires.
Si la mémoire en cache est trop importante, l''opération échoue, ce qui est notre cas ici (30Go)
La mémoire en cache correspond à des pages mémoires régulièrement sollicitées et donc placées dans cet espace pour améliorer les I/O
Il existe plusieurs types de caches mémoires (dont le cache slab présent dans la graphique ci-dessous)

Vue dans l''outil de dashboarding Grafana:
[img src="/api/images/bAFs0Prfqp6LZJuUR2mZweVfvL8Wwj" /]

On peut régler ce soucis en modifiant certaines variables kernels comme indiqué par Red Hat:
https://access.redhat.com/solutions/4065301

Puisqu''il faut un compte pour pouvoir voir la résolution dans l''article, en voici l''extrait:
[img src="/api/images/5bApq2z7WgdIAJJ0h0S7IH7p2WTkhO" /]

Pour ma part, j''ai forcé un vidage de la mémoire cache.
Celle-ci se reconstruira d''elle-même. Cela peut néanmoins impacter les perfs du serveur car si les pages sont en cache, ce n''est pas pour rien. La commande echo doit être faite en root, précédé de la commande sync
[code lg="bash"]
sync; echo 3 > /proc/sys/vm/drop_caches
[/code]

Vérification de la consommation mémoire : buffer/cache à environ 1Go
[code lg="bash"]
free -m
              total        used        free      shared  buff/cache   available
Mem:          60536       20346       38758          35        1432       39384
Swap:         8191        6096        2095
[/code]

On peut enfin activer notre espace de swap
[code lg="bash"]
sudo swapon -v /dev/rootvg/lvswap2
swapon /dev/rootvg/lvswap2
swapon: /dev/mapper/rootvg-lvswap2: found swap signature: version 1, page-size 4, same byte order
swapon: /dev/mapper/rootvg-lvswap2: pagesize=4096, swapsize=8589934592, devsize=8589934592
[/code]

Vérification des espaces de swap
[code lg="bash"]
swapon -s
Filename                                Type            Size    Used    Priority
/dev/dm-0                               partition       8388604 6193852 -2
/dev/dm-37                             partition       8388604 0 -2
[/code]

-s : summary

Plus d''infos sur le cache linux:
https://blog.seboss666.info/2015/08/reprenez-le-controle-du-cache-memoire-du-noyau-linux/
', 'Comment corriger le problème d''allocation mémoire empêchant la création d''un espace de Swap ?', '2020-09-26 13:39:40 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', '4013ecaf-4a1e-485e-91c6-1892885c606d', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('dc313e71-4346-4993-900a-34ce01db3b8e', 'POSTQFI05I2BRZ', 'Tests paramétriques en JUnit 5', '[h1]Introduction[/h1]
[h2]Différence avec JUnit 4[/h2]
Le problème des tests paramétriques avec JUnit 4, c''est que la classe de test qui les héberge, ne peut pas héberger d''autres tests unitaire.
Par conséquent, si on veut tester un service métier dont l''une des fonction peut être testée avec un test paramétrique, alors on devra faire deux classes de test, l''une contenant que le test paramétrique, et les autres tests plus "conventionnels" dans l''autre.
[h1]Code[/h1]
Le test paramétrique :
[code lg="java"]
@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
void isBlank_ShouldReturnTrueForNullOrBlankStrings(String input, boolean expected) {
    assertEquals(expected, Strings.isBlank(input));
}
[/code]

Pour variabiliser les valeurs du test paramétrique, il faut les ajouter en paramètre du test unitaire, comme les paramètres "input" et "expected" dans l''exemple ci-dessus.

Ensuite, ces valeurs doivent être fournies par une méthode statique, celle dont le nom est précisé dans l''annotation "@MethodSource".
Exemple :

[code lg="java"]
private static Stream<Arguments> provideStringsForIsBlank() {
    return Stream.of(
        Arguments.of(null, true),
        Arguments.of("", true),
        Arguments.of("  ", true),
        Arguments.of("not blank", false)
    );
}
[/code]

[h3]Sources[/h3]
[link href="https://www.baeldung.com/parameterized-tests-junit-5" txt="https://www.baeldung.com/parameterized-tests-junit-5" /]', 'Tutoriel pour écrire un test paramétrique en JUnit 5', '2020-10-07 09:03:41 +01:00', 'b4ffa7df-d39e-4970-8fd0-0a27844d8af6', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '61f9fbf3-3340-4ea4-9661-04089377bb2e'),
('500aaa8a-ebc3-4283-a15e-23cb68163553', 'POSTQ4BK6ZT40N', 'Sécuriser Jenkins avec SSL', '[h1]Génération du certificat[/h1]
Comme indiqué sur ce [link href="https://codiki.org/posts/POST15UG2MIB1E" txt="post" /], il faut générer un certificat de type "Java" avec l''outil "keytool".
[code lg="bash"]
keytool -genkeypair -alias <alias_applicatif> -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 365
[/code]

On peut ensuite placer le certificat dans un répertoire nommé "certificates" dans le dossier de Jenkins :
[code lg="bash"]
/var/lib/jenkins/certificates/keystore.p12
[/code]

[h1]Configuration[/h1]
[h2]Version >= 2.332[/h2]
Depuis la version 2.332, jenkins est passé de "System V" à "SystemD" pour son démarrage en tant que service.

Au passage, la configuration a changé et il faut désormais éditer le fichier de configuration suivant :
[code lg="bash"]
/usr/lib/systemd/system/jenkins.service
[/code]


À l''intérieur, il y a un ensemble de propriétés nommées "Environment" qu''il faut modifier comme ce qui suit :
[code lg="bash"]
Environment="JENKINS_HTTPS_PORT=<port>"
Environment="JENKINS_HTTPS_KEYSTORE=<path-to-keystore>/keystore.p12"
Environment="JENKINS_HTTPS_KEYSTORE_PASSWORD=<password>"
[/code]


[h3]Sources[/h3]
[link href="https://community.jenkins.io/t/changing-default-jenkins-port-to-9090-as-tomcat-is-using-the-same-port/3176" txt="https://community.jenkins.io/t/changing-default-jenkins-port-to-9090-as-tomcat-is-using-the-same-port/3176" /]

[h2]Version < 2.332[/h2]
Il faut éditer le fichier de configuration de Jenkins qui se trouve à cet emplacement :
[code lg="bash"]
/etc/default/jenkins
[/code]

Pour y créer des variables liées au certificat SSL, ainsi que pour activer le protocole "https" :

[code lg="bash"]
# port for HTTP connector (default 8080; disable with -1)
HTTP_PORT=-1
HTTPS_PORT=12345
KEY_STORE=''/var/lib/jenkins/certificates/keystore.p12''
KEY_STORE_PWD=''<keystore_password>''
[/code]

Il ne faut pas oublier de modifier la variable "JENKINS_ARGS" afin d''utiliser ces nouvelles variables :

[code lg="bash"]
JENKINS_ARGS="--webroot=/var/cache/$NAME/war --httpPort=$HTTP_PORT --httpsPort=$HTTPS_PORT --httpsKeyStore=$KEY_STORE --httpsKeyStorePassword=$KEY_STORE_PWD"
[/code]

Nouvelle configuration :
[link href="https://www.jenkins.io/doc/book/installing/linux/#debianubuntu" txt="https://www.jenkins.io/doc/book/installing/linux/#debianubuntu" /]
[link href="https://devopscube.com/configure-ssl-jenkins/" txt="https://devopscube.com/configure-ssl-jenkins/" /]', 'Mise en place d''un certificat OpenSSL pour Jenkins', '2023-01-17 15:59:12 +01:00', '4c9dbcba-15a9-4e64-b186-8b266c0c00cb', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('a1951d76-b2dc-41e2-9c5a-06e0bf477d30', 'POSTVBYPOEA22L', 'Mise à jour d''une version obsolète d''Ubuntu', '[h1]Contexte[/h1]
Imaginons qu''on ait installé une version non-LTS d''Ubuntu, comme la version 22.10 (la LTS est la 22.04).

Lorsqu''on fait un "apt update", on obtient l''erreur suivante :

[code lg="bash"]
~$ sudo apt update && sudo apt dist-upgrade
Ign :1 http://fr.archive.ubuntu.com/ubuntu kinetic InRelease
Ign :2 http://fr.archive.ubuntu.com/ubuntu kinetic-updates InRelease
Ign :3 http://fr.archive.ubuntu.com/ubuntu kinetic-backports InRelease
Atteint :4 https://linux.teamviewer.com/deb stable InRelease
Réception de :5 https://download.docker.com/linux/ubuntu hirsute InRelease [48,9 kB]
Err :6 http://fr.archive.ubuntu.com/ubuntu kinetic Release
  404  Not Found [IP : 2001:bc8:1600:4:63f:72ff:feaf:a2de 80]
Err :7 http://fr.archive.ubuntu.com/ubuntu kinetic-updates Release
  404  Not Found [IP : 2001:bc8:1600:4:63f:72ff:feaf:a2de 80]
Atteint :8 https://updates.signal.org/desktop/apt xenial InRelease
Err :9 http://fr.archive.ubuntu.com/ubuntu kinetic-backports Release
  404  Not Found [IP : 2001:bc8:1600:4:63f:72ff:feaf:a2de 80]
Ign :10 http://security.ubuntu.com/ubuntu kinetic-security InRelease
Err :11 http://security.ubuntu.com/ubuntu kinetic-security Release
  404  Not Found [IP : 2620:2d:4002:1::102 80]
Lecture des listes de paquets... Fait
E: Le dépôt http://fr.archive.ubuntu.com/ubuntu kinetic Release ne contient plus de fichier Release.
N: Les mises à jour depuis un tel dépôt ne peuvent s''effectuer de manière sécurisée, et sont donc désactivées par défaut.
N: Voir les pages de manuel d''apt-secure(8) pour la création des dépôts et les détails de configuration d''un utilisateur.
E: Le dépôt http://fr.archive.ubuntu.com/ubuntu kinetic-updates Release ne contient plus de fichier Release.
N: Les mises à jour depuis un tel dépôt ne peuvent s''effectuer de manière sécurisée, et sont donc désactivées par défaut.
N: Voir les pages de manuel d''apt-secure(8) pour la création des dépôts et les détails de configuration d''un utilisateur.
E: Le dépôt http://fr.archive.ubuntu.com/ubuntu kinetic-backports Release ne contient plus de fichier Release.
N: Les mises à jour depuis un tel dépôt ne peuvent s''effectuer de manière sécurisée, et sont donc désactivées par défaut.
N: Voir les pages de manuel d''apt-secure(8) pour la création des dépôts et les détails de configuration d''un utilisateur.
E: Le dépôt http://security.ubuntu.com/ubuntu kinetic-security Release ne contient plus de fichier Release.

[/code]

Et si on tente la commande suivante :

[code lg="bash"]
~$ sudo do-release-upgrade
[/code]

On obtient ça :

[code lg="bash"]
Recherche d''une nouvelle version d''Ubuntu
Votre version d''Ubuntu n''est plus prise en charge.
Pour plus d''informations sur la mise à jour, veuillez visiter :
http://www.ubuntu.com/releaseendoflife

Veuillez installer toutes les mises à jour disponibles pour votre version avant la mise à niveau.

[/code]

C''est dû au fait qu''Ubuntu déplace les paquets des version non-LTS obsolètes dans un autre dépôt.

[h1]Solution[/h1]

Il faut changer d''URL pour les dépôts APT, en modifiant le fichier :

[code lg="bash"]
/etc/apt/sources.list
[/code]

En replaçant :

[code lg="bash"]
http://fr.archive.ubuntu.com/ubuntu
[/code]

Par :

[code lg="bash"]
http://old-releases.ubuntu.com/ubuntu
[/code]

À partir de là, on pourra refaire les mises à jour classiquement :

[code lg="bash"]
~$ sudo apt update && sudo apt upgrade
...
~$ sudo do-release-upgrade
[/code]

Si jamais la commande suivante ne fonctionne pas :
[code lg="bash"]
~$ sudo do-release-upgrade
[/code]

Il faut d''abord lancer la commande suivante avant de pouvoir la refaire :
[code lg="bash"]
~$ sudo apt dist-upgrade
[/code]

', 'Comment passer à une version majeure d''Ubuntu lorsqu''on utilise une version non-LTS périmée', '2023-09-28 18:09:11 +01:00', 'fdc92c27-cfad-4e77-9502-a265fed026e2', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('1fe5c39f-ec9d-40a4-8011-aa68064c038f', 'POSTLKGXWYV62B', 'Afficher grub au démarrage', '[h1]Contexte[/h1]
Après avoir installé Windows puis Ubuntu 23 pour faire un dual boot, mon PC démarrait directement sur Linux, sans afficher le menu de Grub.

Voici comment configurer Grub afin qu''il s''affiche au démarrage du PC.

[h1]Réalisation[/h1]
Il faut modifier le fichier suivant :
[code lg="bash"]
sudo vim /etc/default/grub
[/code]

Et dedans, il faut modifier les entrées suivantes :
- GRUB_TIMEOUT_STYLE
- GRUB_TIMEOUT

[code lg="bash"]
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=10
[/code]


Une fois fait, il faut mettre à jour la configuration de Grub, en lançant cette commande :
[code lg="bash"]
sudo update-grub
[/code]


[h3]Sources[/h3]
[link href="https://askubuntu.com/a/1187104" txt="https://askubuntu.com/a/1187104" /]', 'Configurer grub pour qu''il s''affiche au démarrage si ce n''est pas le cas', '2023-12-20 10:33:35 +01:00', 'c6941027-8c1b-47cd-9640-a602b1d99d15', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90'),
('3eb1ee4a-592b-444d-907a-61f701cfc475', 'POST8LQ3EVSVR5', 'Utilitaires MacOS', '[h1]Description[/h1]

L''adage "Think different", dicté par Steve Jobs n''a jamais été aussi vrai. En effet, l''ergonomie de MacOS est très singulière et peut dérouter pas mal de monde, surtout les utilisateurs venant de Linux ou Windows.

[h2]La gestion des fenêtres[/h2]
La gestion des fenêtres est très particulière, pour mettre en plein écran une fenêtre, il suffit de double-cliquer sur le col de la fenêtre, ce qui lui donnera la taille maximale (sauf dans certains cas, avec certaines applications Apple où la taille augmente mais pas à son maximum...), ou alors de cliquer sur le bouton vert en haut à gauche de la fenêtre, ce qui aura pour conséquence de mettre la fenêtre en mode fullscreen/présentation, en la plaçant dans un bureau virtuel distinct, et où il sera interdit d''ouvrir une autre fenêtre ! ("Think different, my friend"...).

[h2]Le scrolling entre le touchpad et la souris[/h2]
Sur MacOS on nous impose des choix, ce qui est notamment le cas du scrolling. En effet, par défaut c''est le scrolling naturel (qui imite celui d''un écran tactile) qui est configuré. Il est très pertinent lorsqu''on utilise le touchpad, cependant, à la souris c''est plutôt le scrolling non naturel dont les utilisateurs ont l''habitude.

Il est effectivement possible d''inverser le sens du scrolling, mais cela sera effectif à la fois pour le touchpad ET pour la souris. Il est impossible, nativement, de configurer un scrolling naturel pour le touchpad, et un scrolling non naturel pour la souris.

[h1]Solutions[/h1]
[h2]Rectangle - La gestion des fenêtres[/h2]
Il existe une application opensource qui permet de gérer les fenêtre comme sur Linux ou Windows. Il s''agit de "Rectangle".

[img src="/api/images/c5d4u2V4m3sAu7TNmSbbqLgXIEYex8" /]

Cette application permet de gérer les raccourcis clavier pour agrandir une fenêtre, la mettre sur la moitié droite de l''écran etc... mais également en mode drag-and-drop avec la souris.

Voici les raccourcis équivalents à Linux/Windows :
 - Mettre en plein écran
    - super + Up -> ctrl + option + Enter
 - Mettre sur la moitié droite (fonctionne de la même manière pour la gauche)
    - super + Right -> ctrl + option + Right

[link href="https://rectangleapp.com/" txt="Site de l''application Rectangle" /]

[h2]Sroll Reverser - Le scrolling entre le touchpad et la souris[/h2]
L''application s''appelle "Scroll Reverser".

[img src="/api/images/86swAGYaxldqLITZ1FZgxQLQFqwsSM" /]

[link href="https://pilotmoon.com/scrollreverser/" txt="Site de l''application Scroll Reverser" /]

Attention, pensez à ne pas cocher l''option "Inverser Pavé Tactile".

[h2]MiddleClick - Le "clic molette" au touchpad[/h2]
L''application s''appelle "MiddleClick".

[img src="/api/images/013aEcumfihQ7w4OnBmR4OSHGJQRzh" /]

Attention, selon la version de MacOS, il faudra trouver les autres dépôts git car les versions ne sont pas compatibles d''une version d''OS à une autre.

[link href="https://github.com/artginzburg/MiddleClick-Ventura" txt="Site de l''application MiddleClick" /]

[h2]AltTab - Le changement de fenêtres comme sur Linux/Windows[/h2]
Le système de base de changement de fenêtres de MaxOS accessible via le raccourci "Cmd + Tab" a un comportement légèrement différent de celui des autres OS : Il permet de basculer non pas entre les fenêtres, mais entre les applications. Ce qui signifie que si vous avez plusieurs fenêtres de votre navigateur d''ouvertes, vous ne pourrez pas basculer de l''une vers l''autre via ce raccourcis clavier.

L''outil "AltTab" permet justement de changer ce comportement afin de retrouver une bascule entre les fenêtres et non les applications.

[link href="https://alt-tab-macos.netlify.app/" txt="https://alt-tab-macos.netlify.app/" /]

[h2]Hidden bar - Masquer des icônes dans la barre d''état en haut de l''écran[/h2]
[link href="https://github.com/dwarvesf/hidden" txt="https://github.com/dwarvesf/hidden" /]', 'Liste d''applications à installer pour survivre sur MacOS', '2024-02-15 09:54:24 +01:00', 'c3d35742-f030-4e5f-b057-d8c9e2b0c5e0', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '7234cd9e-3834-45c5-973b-1574f5c3c4c6'),
('da2be5c9-f62d-4dd8-a18c-4414ff5b9038', 'POST7NQ1NA5DQ6', 'Lanceurs d''applications sur Gnome', '[h1]Contexte[/h1]

Il se peut que certains logiciels ne soient pas installable via les dépôts publiques ou privés d''apt. Par conséquent, on peut être amené à l''installer manuellement, ce qui se traduit souvent par le téléchargement d''une archive tar.gz.

Dans ce cas, il n''existe pas de lanceur de l''application dans l''environnement Gnome. Ce post a pour objectif d''expliquer comment en créer un.

[h1]Alacarte - Utilitaire de création de lanceurs[/h1]

Le logiciel "Alacarte" permet de créer les lanceurs sur Gnome.

Pour l''installer :
[code lg="bash"]
sudo apt install alacarte
[/code]

Voici à quoi ressemble l''outil :
[img src="/api/images/IkthV0PMOZlxsOYUkOsqFPFKgzmm1X" /]

Pour créer un lanceur, il suffit de cliquer sur le bouton "Nouvel élément" et de remplir les champs du formulaire dans la popup qui s''ouvrira.

Attention, dans le champ "command", il faut taper une commande "bash" qui sera exécutée lorsqu''on exécutera le lanceur d''application. On ne peut donc pas saisir uniquement le chemin vers un script bash, il faudra le préfixer par le chemin absolu de l''interpréteur bash.

Exemple :
[code lg="bash"]
/bin/bash /home/$USER/logiciel/script.sh
[/code]

Une fois le formulaire de la popup validée, le logiciel "Alacarte" créera un fichier "alacarte-X.desktop" dans le répertoire suivant :
[code lg="bash"]
/home/$USER/.local/share/applications/
[/code]

Dans ce fichier de configuration, vous retrouverez les informations que vous aurez saisi pour créer le lanceur d''application.

[h2]Épingler le nouveau lanceur au dock[/h2]
Une fois le lanceur créé, il se peut qu''on ne puisse pas l''épingler au dock, parce que l''option ne sera pas présente lorsqu''on fait un clic droit sur le lanceur depuis le dock.

Pour remédier à cela, il faudra modifier le fichier "xxx.desktop" généré par "Alacarte", pour y préciser une information technique.

Avant ça, il va falloir déterminer une propriété du logiciel que votre nouveau lanceur exécute.

Pour cela, il faut ouvrir le dit logiciel, puis ouvrir un terminal et taper la commande suivante :
[code lg="bash"]
xprop WM_CLASS
[/code]

Et enfin, il suffit de cliquer sur le logiciel concerné par le nouveau lanceur. Ça aura pour effet d''écrire une classe de fenêtre dans le terminal où vous aurez tapé la commande précédente.

Exemple :
[code lg="bash"]
$ xprop WM_CLASS
WM_CLASS(STRING) = "jetbrains-idea-ce", "jetbrains-idea-ce"
[/code]

Une fois fait, vous pouvez copier l''une des valeurs entre double-quotes dans la sortie du terminal, puis ouvrez le fichier "xxx.desktop" qu''Alacarte vous a précédemment généré.

Puis, ajoutez ce contenu dans le fichier :
[code lg="bash"]
StartupWMClass=<WM_CLASS>
[/code]

Exemple :
[code lg="bash"]
StartupWMClass=jetbrains-idea-ce
[/code]

Une fois fait, enregistrez la modification, fermez le logiciel puis relancez le à partir du lanceur que vous avez créé, et vous pourrez l''épingler au dock.

[h3]Sources[/h3]
[link href="https://askubuntu.com/a/1378648" txt="https://askubuntu.com/a/1378648" /]', 'Création d''un lanceur d''application sur Gnome', '2024-01-05 12:11:05 +01:00', 'feadaf61-22a1-4722-baf1-b8e26dda7075', 'd1d557a6-88b1-4274-994e-f9a9a6097997', '0f4c4d7c-2ccc-4725-88b6-672aa518da90');
