diff --git a/docs/workshop/en/README.md b/docs/workshop/en/README.md
new file mode 100644
index 0000000..227ec59
--- /dev/null
+++ b/docs/workshop/en/README.md
@@ -0,0 +1,36 @@
+# How to build the workshop
+
+## Flat HTML output with pandoc
+
+~~~
+pandoc -s -o /tmp/workshop-PAF.html workshop-PAF.md
+~~~
+
+## Slide output with reveal and pandoc
+
+Download and extract reveal.js to /tmp/reveal.js:
+
+~~~
+cd /tmp
+wget https://github.com/hakimel/reveal.js/archive/master.zip
+unzip master.zip
+mv reveal.js-master reveal.js
+~~~
+
+Now you can build a self-contained html file:
+
+~~~
+pandoc -t revealjs --variable=revealjs-url:/tmp/reveal.js workshop-PAF.md --self-contained --standalone -o /tmp/paf.html
+~~~
+
+Note: if you have an internet access you can build html files without downloading and extracting reveal.js (but speaker notes will not work):
+
+~~~
+pandoc -t revealjs --variable=revealjs-url:http://lab.hakim.se/reveal-js workshop-PAF.md --self-contained --standalone -o /tmp/paf.html
+~~~
+
+## PDF output with pandoc
+
+~~~
+pandoc workshop-PAF.md -o /tmp/paf.pdf
+~~~
diff --git a/docs/workshop/en/medias/Makefile b/docs/workshop/en/medias/Makefile
new file mode 100644
index 0000000..63c1f99
--- /dev/null
+++ b/docs/workshop/en/medias/Makefile
@@ -0,0 +1,72 @@
+# export png:
+# make DRAWIO_HOME=/home/ioguix/git/drawio-desktop
+
+DRAWIO_HOME=/change/me
+DRAWIO=npm start --prefix "$(DRAWIO_HOME)" -- --no-sandbox -x -f png --border=30 --height=800
+
+ALLPNG=pcmk-archi-all.png pcmk-archi-cib.png pcmk-archi-crmd.png
+ALLPNG+=pcmk-archi-fencing.png pcmk-archi-pengine.png pcmk-archi-resource.png
+ALLPNG+=pcmk-archi-dc.png pcmk-archi-transition.png pcmk-archi-paf-overview.png
+ALLPNG+=paf-ms-roles.png paf-ms-roles-notify.png paf-election.png
+ALLPNG+=paf-standby-recover.png paf-primary-recover.png
+
+
+all: $(ALLPNG)
+
+clean:
+ rm -f $(ALLPNG)
+
+pcmk-archi-all.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=0 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-cib.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=1 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-crmd.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=2 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-dc.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=3 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-fencing.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=4 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-pengine.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=5 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-resource.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=6 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-paf-overview.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=7 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+pcmk-archi-transition.png: $(CURDIR)/pcmk-archi.xml
+ $(DRAWIO) --page-index=8 -o "$(CURDIR)/$@" $(CURDIR)/pcmk-archi.xml
+
+paf-ms-roles.png: $(CURDIR)/paf-mecha.xml
+ $(DRAWIO) --page-index=0 -o "$(CURDIR)/$@" $(CURDIR)/paf-mecha.xml
+
+paf-ms-roles-notify.png: $(CURDIR)/paf-mecha.xml
+ $(DRAWIO) --page-index=1 -o "$(CURDIR)/$@" $(CURDIR)/paf-mecha.xml
+
+paf-standby-recover.png: $(CURDIR)/paf-mecha.xml
+ $(DRAWIO) --page-index=2 -o "$(CURDIR)/$@" $(CURDIR)/paf-mecha.xml
+
+paf-primary-recover.png: $(CURDIR)/paf-mecha.xml
+ $(DRAWIO) --page-index=3 -o "$(CURDIR)/$@" $(CURDIR)/paf-mecha.xml
+
+paf-election.png: $(CURDIR)/paf-mecha.xml
+ $(DRAWIO) --page-index=4 -o "$(CURDIR)/$@" $(CURDIR)/paf-mecha.xml
+
+# paf-mecha.xml
+# pcmk-archi.xml
+# pcmk-archi-cib.png
+# pcmk-archi-crmd.png
+# pcmk-archi-dc.png
+# pcmk-archi-fencing.png
+# pcmk-archi-pengine.png
+# pcmk-archi.png
+# pcmk-archi-resource.png
+# pcmk-archi.png
+# pcmk-archi.xml
+# Policy-Engine-big.png
diff --git a/docs/workshop/en/medias/Policy-Engine-big.png b/docs/workshop/en/medias/Policy-Engine-big.png
new file mode 100644
index 0000000..e6e66ee
Binary files /dev/null and b/docs/workshop/en/medias/Policy-Engine-big.png differ
diff --git a/docs/workshop/en/medias/README b/docs/workshop/en/medias/README
new file mode 100644
index 0000000..6d81e7c
--- /dev/null
+++ b/docs/workshop/en/medias/README
@@ -0,0 +1,14 @@
+Diagrams have been generated using draw.io from https://www.draw.io/.
+
+To modify it, go to the website and "Open Existing Diagram" or install draw.io
+localy.
+
+Select the .xml source file.
+
+Do your modification and Save.
+
+To generate the png and svg files, select "Export as" or use the Makefile.
+Eg.:
+
+ make DRAWIO_HOME=$HOME/git/drawio-desktop all
+
diff --git a/docs/workshop/en/medias/paf-election.png b/docs/workshop/en/medias/paf-election.png
new file mode 100644
index 0000000..9e40dc6
Binary files /dev/null and b/docs/workshop/en/medias/paf-election.png differ
diff --git a/docs/workshop/en/medias/paf-mecha.xml b/docs/workshop/en/medias/paf-mecha.xml
new file mode 100644
index 0000000..3ce451a
--- /dev/null
+++ b/docs/workshop/en/medias/paf-mecha.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/docs/workshop/en/medias/paf-ms-roles-notify.png b/docs/workshop/en/medias/paf-ms-roles-notify.png
new file mode 100644
index 0000000..e1658c2
Binary files /dev/null and b/docs/workshop/en/medias/paf-ms-roles-notify.png differ
diff --git a/docs/workshop/en/medias/paf-ms-roles.png b/docs/workshop/en/medias/paf-ms-roles.png
new file mode 100644
index 0000000..5b0a665
Binary files /dev/null and b/docs/workshop/en/medias/paf-ms-roles.png differ
diff --git a/docs/workshop/en/medias/paf-primary-recover.png b/docs/workshop/en/medias/paf-primary-recover.png
new file mode 100644
index 0000000..cb23a88
Binary files /dev/null and b/docs/workshop/en/medias/paf-primary-recover.png differ
diff --git a/docs/workshop/en/medias/paf-standby-recover.png b/docs/workshop/en/medias/paf-standby-recover.png
new file mode 100644
index 0000000..510a3a1
Binary files /dev/null and b/docs/workshop/en/medias/paf-standby-recover.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-all.png b/docs/workshop/en/medias/pcmk-archi-all.png
new file mode 100644
index 0000000..171f776
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-all.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-cib.png b/docs/workshop/en/medias/pcmk-archi-cib.png
new file mode 100644
index 0000000..0261649
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-cib.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-crmd.png b/docs/workshop/en/medias/pcmk-archi-crmd.png
new file mode 100644
index 0000000..b6190cc
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-crmd.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-dc.png b/docs/workshop/en/medias/pcmk-archi-dc.png
new file mode 100644
index 0000000..cae44a5
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-dc.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-fencing.png b/docs/workshop/en/medias/pcmk-archi-fencing.png
new file mode 100644
index 0000000..016bf1f
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-fencing.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-paf-overview.png b/docs/workshop/en/medias/pcmk-archi-paf-overview.png
new file mode 100644
index 0000000..4ffa9ac
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-paf-overview.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-pengine.png b/docs/workshop/en/medias/pcmk-archi-pengine.png
new file mode 100644
index 0000000..14806bb
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-pengine.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-resource.png b/docs/workshop/en/medias/pcmk-archi-resource.png
new file mode 100644
index 0000000..5a7c9a5
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-resource.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi-transition.png b/docs/workshop/en/medias/pcmk-archi-transition.png
new file mode 100644
index 0000000..f27fd45
Binary files /dev/null and b/docs/workshop/en/medias/pcmk-archi-transition.png differ
diff --git a/docs/workshop/en/medias/pcmk-archi.xml b/docs/workshop/en/medias/pcmk-archi.xml
new file mode 100644
index 0000000..3ce7d49
--- /dev/null
+++ b/docs/workshop/en/medias/pcmk-archi.xml
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/docs/workshop/en/prerequisites.md b/docs/workshop/en/prerequisites.md
new file mode 100644
index 0000000..e5c1d9b
--- /dev/null
+++ b/docs/workshop/en/prerequisites.md
@@ -0,0 +1,49 @@
+# Prerequisites
+
+Before attending to this workshop, attendees should have prepared their
+computer with the following:
+
+* libvirtd
+* virt-manager
+* 3 VM running CentOS 7
+* SSH authentication between the VM -> user@hypervisor
+* the VM should be able to ping each other
+
+## Preparation of the VM
+
+* Exchange SSH keys between the root users on the VM and the hypervisor user:
+
+ ~~~
+ ssh-keygen
+ ssh-copy-id @
+ ~~~
+
+* The VM should be able to communicate between each other using their node
+ names, e.g.:
+
+ ~~~
+ cat >> /etc/hosts <.
+In this case some data has not been replicated from the old primary to the new
+one before the switchover. As a result, several days were needed to restore the
+lost data in the newly build cluster.
+
+Never underestimate the innovative nature of incidents, and the likelihood that
+they will partition your cluster. Here are some more examples:
+.
+
+Note that PAF is build with fencing enabled clusters in mind. Should a
+failure occurs, no failover will occur if your cluster is not able to fence the
+relevant resource.
+
+:::
+
+-----
+
+## Quorum
+
+* which part of the cluster should keep operating during a network partition?
+ * each cluster member has one vote
+ * the cluster keeps running only if it has the majority of the votes
+
+::: notes
+
+The quorum is the minimum number of votes requiered for a distributed
+transaction to be authorized to execute an operation on the system. It's goal
+is to guaranty the coherence of the distributed system.
+
+To achieve this goal, each node is granted some votes. A minimum of `(N / 2) +
+1` votes are required to grant the quorum, `N` being the maximum number
+of vote possible). The cluster will be able to operate only if the majority
+of node is available.
+
+After a network partition, the cluster relies on the quorum information to
+decide on which partition the services must runs, and which partition must stop
+all of them. Fencing operation can be started if necessary.
+
+In addition to stopping all local services, a cluster partition who doesn't meet
+the quorum cannot use fencing operation against remote nodes.
+
+
+
+This mecanism is paramount for the cluster to operate correctly.
+
+:::
+
+-----
+
+## KISS
+
+* a complex architecture brings its own complex problems:
+ * to build (avoid a _SPOF_)
+ * to maintain
+ * to document
+* it's advised to aim for simplicity first and foremost
+
+
+::: notes
+
+Increasing the complexity of a cluster also increases the number of failures
+scenarios. Given two cluster implementations, the simplest one will usually be
+the best and most sustainable.
+
+The outage described by Grocardless in the following hyperlink is a good
+example of this. The article describes how automation erodes the knowledge of
+the architecture and how it's difficult ot keep the documentation up to date
+and the team trained:
+
+[Incident review: API and Dashboard outage on 10 October
+2017](https://gocardless.com/blog/incident-review-api-and-dashboard-outage-on-10th-october/)
+
+> **Automation erodes knowledge**
+>
+> It turns out that when your automation successfully handles failures for two
+years, your skills in manually controlling the infrastructure below it atrophy.
+There's no "one size fits all" here. It's easy to say "just write a runbook",
+but if multiple years go by before you next need it, it's almost guaranteed to
+be out-of-date.
+
+:::
+
+-----
+
+## History
+
+-----
+
+### History of Pacemaker
+
+* several projects on different platforms
+ * Linux HA project led by SUSE
+ * "Cluster Services" by Red Hat
+* 2007: Pacemaker appears
+ * originated from Linux-HA
+ * first projects convergence
+
+::: notes
+
+The complete history is available
+[here](https://www.alteeve.com/w/High-Availability_Clustering_in_the_Open_Source_Ecosystem).
+
+Several companies have build a long standing experience in the field of high
+availability and provide solution dedicated to it.
+
+SUSE is one of them with the project Linux-HA. Red Hat is also known for their
+"Cluster Services".
+
+In 2007, a first collaborative work leads to the birth of Pacemaker. This
+solution is designed to operate clusters over the different communication
+layers avaiable at that time: OpenAIS (Reh Hat) or Heartbeat (SUSE).
+
+:::
+
+-----
+
+### Historique de Pacemaker - suite
+
+* 2009 : Corosync appears
+ * based on OpenAIS
+ * 2nd convergence
+* 2014 : harmonisation starts
+
+::: notes
+
+In 2009, an effort to standarize the communication layers leads to the birth of
+Corosync.
+
+A strong collaboration is born, Pacemaker and Corosync are becoming the
+reference for Linux high availability and all the Linux distributions start to
+include these tools in their packaging.
+
+:::
+
+-----
+
+### History of Pacemaker - future
+
+* 2017: the main distribution have converged
+ * Corosync 2.x and Pacemaker 1.1.x
+* 2018: corosync 3 and Pacemaker 2.0.x
+
+::: notes
+
+In 2017, the latest versions of the main Linux distributions are done
+converging to Corosync 2.x and Pacemaker 1.1.x. The last difference between
+them is the chosen cluster administration tool: `crmsh` or `pcs`.
+
+Early 2018, Pacemaker 2.0 and Corosync 3.0 are release. On the Pacemaker side,
+the main changes are :
+
+* the removal of a lot of code dedicated to old architectures: OpenAIS, CMAN,
+ Corosync 1.x and Heartbeat compatibility is dropped.
+* several configuration parameters have been removed or replaced with others in
+ an effort to make the configuration more consistent.
+
+More information is available here:
+
+In regard with Corosync, the main novelty is the availability of "Kronosnet" as
+communication protocol. This library allows for more flexibility, adds more
+functionality, ease the supervision of Corosync and decreases the
+latency. Some of the novelties are listed below :
+
+* support for up to 8 network links
+* support for the addition of network without restart
+* support for multiple protocols in different links
+* several algorithm to manage links (active/passive or active/active)
+* support for compression and encryption
+
+More information is available here: [Kronosnet:The new face of Corosync communications](http://build.clusterlabs.org/corosync/presentations/2017-Kronosnet-The-new-face-of-corosync-communications.pdf)
+
+:::
+
+-----
+
+## Administration tools
+
+* `crmsh`
+ * original tool
+ * management and configuration of the cluster
+ * rely on ssh
+* `pcs`
+ * introduced by Red Hat
+ * management and configuration of the cluster
+ * rely on its own communication daemons `pcsd`
+ * used in this workshop
+
+::: notes
+
+The tool `cmrsh` originates to the beginning of the Pacemaker project. This
+tool is designed to managed and configure the cluster without requiering to
+modify the configuration files. It's mostly maintained by SUSE, and sometimes
+presents incompatibilities with other distribution in the creation, starting
+and stopping process of the cluster. Nevertheless, the tool evolves quickly and
+several incompatibilities have been fixed.
+
+When Red Hat adopted Pacemaker, a new tool was created: `pcs`. It regroups all
+the Pacemaker commands along with those for Corosync (and CMAN in the versions
+for EL 6). It includes an HTTP service to configure and maintain the cluster
+via a web browser.
+
+`crmsh` uses SSH and csync2 to execute commands on the remote servers (via the
+`parallax` python library) and manage the configuration across all servers.
+
+To archive the same tasks, the `pcsd` daemons exchange commands via their web
+services. The `pcsd` daemon manages the communication for the HTTP API
+dedicated to inter-server commands and the HTTP administrator frontend.
+
+When a command requiers a system operation (outside of Pacemaker), the `pcsd`
+daemons communicate and exchange the commands to execute using the HTTP API.
+The command that use this API range from the cluster creation or destruction,
+starting or stopping process and the addition or removal a node, etc.
+
+In 2018, `pcs` is fully integrated into Debian. `crmsh` is still used in
+piority in SUSE, it's also often used in Debian and Ubuntu since it's the
+historic choice for thoses platforms. It remains a good choise as long as the
+administrator doesn't need to interact with the system itself.
+
+**This workshop is based on Centos 7 and uses the `pcs` tool.**
+
+:::
+
+-----
+
+## Available versions
+
+* RHEL 7 and Debian 9:
+ * Corosync 2.x
+ * Pacemaker 1.1.x
+
+* RHEL 8 and Debian 10:
+ * Corosync 3.x
+ * Pacemaker 2.0.x
+
+
+::: notes
+
+The recommended (and supported) version depending on the distribution are:
+
+| OS | Corosync | Pacemaker | Administration tool |
+|:---------:|:--------:|:---------:|------------------------------|
+| EL 7 | 2.x | 1.1.x | pcsd 0.9 |
+| EL 8 | 3.x | 2.0.x | pcsd 0.10 |
+| Debian 9 | 2.4 | 1.1.x | pcs 0.9 or crmsh 2.3 |
+| Debian 10 | 3.0 | 2.0.x | pcs 0.10 or crmsh 4.0 |
+| Debian 11 | 3.1 | 2.0.x | pcs 0.10 or crmsh 4.2 |
+
+By the time of Debian 9, the cluster initialization with `crmsh` 2.x was not
+working with Debian. The 3.x version of `crmsh` supported the cluster
+initialization with some manual intervention and integration errors. The main
+branch of the project is now 4.x, but authors of this workshop never tested it.
+
+Despite `crmsh` is the historical administration tool for Debian based OS, the
+use of `pcsd` and `pcs` is fully operational since Debian 9. See:
+
+
+:::
+
+-----
+
+# First steps with Pacemaker
+
+This chapter takes up the installation and start-up of Pacemaker. The objective
+is to quickly create an empty cluster that we will populate and learn from
+during this workshop.
+
+-----
+
+## Installation
+
+Mandatory packages:
+
+* `corosync`: messaging layer
+* `pacemaker`: cluster orchestration
+* `pcs`: administration tool
+
+:::notes
+
+The installation of Pacemaker is made simple by using the `pacemaker` package
+available from the CentOS 7 official repositories. Note that the `corosync` and
+the `resource-agents` packages are also installed as dependencies.
+
+More details about the packages:
+
+* `corosync`: manages the communication between nodes, the group membership and
+ the quorum
+* `pacemaker`: orchestrates the cluster, reacts to events, takes decisions and
+ performs actions
+* `resource-agents` (_RA_): are a collection of scripts that share a common API
+ and allow Pacemaker to control and monitor different kind of resources.
+
+The `corosync` package installs several tools common to all Linux distributions.
+We will describe them later on:
+
+* `corosync-cfgtool`
+* `corosync-cmapctl`
+* `corosync-cpgtool`
+* `corosync-keygen`
+* `corosync-quorumtool`
+
+Pacemaker also installs it's share of binaries that are common across all Linux
+distributions. Some of them are listed below we might use them in this workshop
+or are commonly discussed in Pacemaler related topics:
+
+* `crm_attribute`
+* `crm_node`
+* `attrd_updater`
+* `cibadmin`
+* `crm_mon`
+* `crm_report`
+* `crm_resource`
+* `crm_shadow`
+* `crm_simulate`
+* `crm_verify`
+* `stonith_admin`
+
+A lots of other tools are installed on all distributions, but their use cases
+are limited to some debug activities or used only by the agents.
+
+The administration tools `pcs` and `crm` rely heavily on these tools and create
+a unified interface to manage the cluster. Even thought cluster admnistration
+tasks can be performed without these tools, they are very usefull and ease
+cluster management to a great degree. Moreover, they carry a fair amount of best
+practices for the supported commands.
+
+During this workshop, we will be using `pcs` to simplify the deployment and
+administration of the cluster. In addition to it's simplicity, the tool works
+the same on all Linux distributions, most notably Debian, EL and their
+derivatives.
+
+The packages install both the CLI `pcs` and the daemon `pcsd`. The latter is
+responsible for the configuration and commands propagation across the nodes.
+
+:::
+
+-----
+
+### Practical work: Installation of Pacemaker
+
+::: notes
+
+1. install the required packages
+2. verify which dependencies were installed
+
+:::
+
+-----
+
+### Correction: Installation of Pacemaker
+
+::: notes
+
+1. Install the required packages
+
+~~~console
+# yum install -y pacemaker
+~~~
+
+2. verify which dependencies were installed
+
+Check the output of the previous command:
+
+~~~
+Dependency Installed:
+[...]
+ corosync.x86_64 0:2.4.3-6.el7_7.1
+ pacemaker-cli.x86_64 0:1.1.20-5.el7_7.2
+ resource-agents.x86_64 0:4.1.1-30.el7_7.4
+~~~
+
+The `corosync`, `resource-agents` and `pacemaker-cli` packages have been
+installed as dependencies of `pacemaker`.
+
+All the required tools to manage a Pacemaker cluster are installer. Most
+notably:
+
+~~~console
+# ls /sbin/crm* /sbin/corosync*
+
+/sbin/corosync /sbin/corosync-cfgtool /sbin/corosync-cmapctl
+/sbin/corosync-cpgtool /sbin/corosync-keygen /sbin/corosync-notifyd
+/sbin/corosync-quorumtool
+
+/sbin/crmadmin /sbin/crm_attribute /sbin/crm_diff
+/sbin/crm_error /sbin/crm_failcount /sbin/crm_master
+/sbin/crm_mon /sbin/crm_node /sbin/crm_report
+/sbin/crm_resource /sbin/crm_shadow /sbin/crm_simulate
+/sbin/crm_standby /sbin/crm_ticket /sbin/crm_verify
+~~~
+
+:::
+
+-----
+
+### Practical work: Installation of `pcs`
+
+::: notes
+
+1. install the `pcs` package
+2. enable the `pcsd` daemon so that it starts on server boots, and start it.
+
+:::
+-----
+
+### Correction: Installation of `pcs`
+
+::: notes
+
+1. install the `pcs` package
+
+~~~console
+# yum install -y pcs
+~~~
+
+2. enable the `pcsd` daemon so that it starts on server boots, and start it.
+
+~~~console
+# systemctl enable --now pcsd
+~~~
+
+or
+
+~~~console
+# systemctl enable pcsd
+# systemctl start pcsd
+~~~
+
+:::
+
+-----
+
+## Cluster creation
+
+* authenticate all `pcsd` daemons with each others
+* create the cluster using `pcs`
+ - this creates the corosync configuration on all servers
+* configures the behavior of Pacemaker's processes
+
+::: notes
+
+Cluster creation is done by creating the same Corosync configuration file on all
+nodes, then starting Pacemaker on them.
+
+Using `pcs` simplifies this process since it creates the configuration files
+everywhere itself. However, this magical step requires that all `pcsd` dameons
+are authenticated with each other so they can exchange of commands using the
+HTTP API. This can be done with the command `pcs cluster auth [...]`.
+
+Once this is done, it's easy to create the cluster using `pcs cluster setup
+[...]`.
+
+The Pacemaker configuration file deals with the behavior of Pacemaker's
+processes, not the cluster management. Information such as where are the traces
+and what is logged can be found there. On the EL familly, the file is stored in
+the `/etc/sysconfig/pacemaker` directory. On Debian, it's located in
+`/etc/default/pacemaker`. This file is relevant only for the local instance of
+Pacemaker. Unlike Corosync's configuration, each node can have a different
+file, but this practice is not recommended.
+
+:::
+
+-----
+
+### Practical work: pcs authentication
+
+::: notes
+
+1. create a password for the `hacluster` user on each node.
+
+The `pcs` tool uses the `hacluster` system user for the authentication with
+`pcsd`. Since the cluster management commands can be executed from any member
+of the cluster, it is advised to configure the same password on all node to
+avoid mixing them up.
+
+2. authenticate all cluster members with each other
+
+Note: since Pacemaker 2, the command must be executed on each node of the
+cluster.
+
+:::
+
+-----
+
+### Correction: pcs authentiation
+
+::: notes
+
+1. create a password for the `hacluster` user on each node.
+
+~~~console
+# passwd hacluster
+~~~
+
+2. authenticate all cluster members with each other
+
+~~~console
+# pcs cluster auth hanode1 hanode2 hanode3 -u hacluster
+~~~
+
+:::
+
+-----
+
+### Practical work: Cluster creation with pcs
+
+::: notes
+
+The `pcs` commands can be executed from any node.
+
+1. create a cluster called `cluster_tp` with three node `hanode1`, `hanode2` and
+ `hanode3`
+2. find the corosync configuration file on all three nodes
+3. check that the configuration file is identical on all three nodes
+4. enable the debug mode in Pacemaker for the `crmd`, `pengine`, `attrd` and
+ `lrmd` sub processes.
+
+We activate the debug mode for the `crmd`, `pengine`, `attrd` and `lrmd` in
+order to have an easier time studying Pacemaker. This will be very useful during
+the workshop.
+
+:::
+
+-----
+
+### Correction: Cluster creation with pcs
+
+::: notes
+
+The `pcs` commands can be executed from any node.
+
+1. create a cluster called `cluster_tp` with three node `hanode1`, `hanode2` and
+ `hanode3`
+
+~~~console
+# pcs cluster setup --name cluster_tp hanode1 hanode2 hanode3
+~~~
+
+2. find the corosync configuration file on all three nodes
+
+Corosync's configuration file is located here: `/etc/corosync/corosync.conf`.
+
+3. check that the configuration file is identical on all three nodes
+
+~~~console
+root@hanode1# md5sum /etc/corosync/corosync.conf
+564b9964bc03baecf42e5fa8a344e489 /etc/corosync/corosync.conf
+
+root@hanode2# md5sum /etc/corosync/corosync.conf
+564b9964bc03baecf42e5fa8a344e489 /etc/corosync/corosync.conf
+
+root@hanode3# md5sum /etc/corosync/corosync.conf
+564b9964bc03baecf42e5fa8a344e489 /etc/corosync/corosync.conf
+~~~
+
+4. enable the debug mode in Pacemaker for the `crmd`, `pengine`, `attrd` and
+ `lrmd` sub processes.
+
+Edit the `PCMK_debug` variable in the configuration file
+`/etc/sysconfig/pacemaker`:
+
+~~~console
+PCMK_debug=crmd,pengine,lrmd,attrd
+~~~
+
+You can trace all the debug messages from all processes by setting this
+parameter to `yes`.
+
+:::
+
+-----
+
+## Cluster startup
+
+FR * cluster créé mais pas démarré
+FR * désactiver Pacemaker au démarrage des serveurs
+FR * utilisation de `pcs` pour démarrer le cluster
+FR
+* the cluster is created but not started
+* disable Pacemaker on server startup
+* use `pcs` to start the cluster
+
+::: notes
+
+FR Une fois le cluster créé, ce dernier n'est pas démarré automatiquement. Il est
+FR déconseillé de démarrer Pacemaker automatiquement au démarrage des serveurs. En
+FR cas d'incident et de fencing, un nœud toujours défaillant pourrait déstabiliser
+FR le cluster et provoquer des interruptions de services suite à un retour
+FR automatique prématuré. En forçant l'administrateur à devoir démarrer Pacemaker
+FR manuellement, celui-ci a alors tout le loisir d'intervenir, d'analyser
+FR l'origine du problème et éventuellement d'effectuer des actions correctives
+FR avant de réintégrer le nœud, sain, dans le cluster.
+FR
+The cluster is not automatically started once it's creation. It's discouraged
+to enable Pacemaker's startup at boot time. In case of outage or fencing, a
+failing node could destabilize the cluster and provoque a downtime because
+it joined the cluster prematurely. By forcing the administrator to start
+Pacemaker manually, we give him time to intervene, analyze the origin of the
+problem and conduct corrective mesure if necessary, before reintroducing the
+node into the cluster.
+
+FR Le démarrage du cluster nécessite la présence des deux services Corosync et
+FR Pacemaker sur tous les nœuds. Démarrer d'abord les services Corosync puis
+FR Pacemaker. À noter que démarrer Pacemaker suffit souvent sur de nombreuses
+FR distributions Linux, Corosync étant démarré automatiquement comme dépendance.
+FR
+Cluster startup requires the presence of the Corosync and Pacemaker services on
+all nodes. Corosync should be started first then Pacemaker. On most Linux
+distribution, starting Pacemaker is enough, since Corosync will be started
+automatically as a dependency.
+
+FR Plutôt que de lancer manuellement Pacemaker sur chaque nœud, il est possible
+FR de sous traiter cette tâche aux daemons `pcsd` avec une unique commande `pcs`.
+FR
+Instead of starting Pacemaker manually on each node, it's possible to delagate
+this task to the `pcsd` daemons thanks to a single `pcs` command.
+
+:::
+
+-----
+
+### Practical work: Starting the cluster
+
+::: notes
+
+FR 1. désactiver Pacemaker et Corosync au démarrage du serveur
+FR 2. démarrer Pacemaker et Corosync sur tous les nœuds à l'aide de `pcs`
+FR 3. vérifier l'état de Pacemaker et Corosync
+FR
+1. deactivate Pacemaker and Corosync at server startup
+2. start Pacemaker and Corosync on all nodes using `pcs`
+3. verify the state of Pacemaker and Corosync
+
+:::
+
+-----
+
+### Correction: Starting the cluster
+
+::: notes
+
+FR 1. désactiver Pacemaker et Corosync au démarrage du serveur
+FR
+FR Sur tous les serveurs:
+FR
+1. deactivate Pacemaker and Corosync at server startup
+
+On all servers:
+
+~~~console
+# systemctl disable corosync pacemaker
+~~~
+
+FR Ou, depuis un seul des serveurs:
+FR
+Or from one of the servers:
+
+~~~console
+# pcs cluster disable --all
+~~~
+
+FR 2. démarrer Pacemaker et Corosync sur tous les nœuds à l'aide de `pcs`
+FR
+2. start Pacemaker and Corosync on all nodes using `pcs`
+
+~~~console
+# pcs cluster start --all
+~~~
+
+FR 3. vérifier l'état de Pacemaker et Corosync
+FR
+FR Sur chaque serveur, exécuter:
+FR
+3. verify the state of Pacemaker and Corosync
+
+On each server, execute:
+
+~~~
+# systemctl status pacemaker corosync
+~~~
+
+Or:
+
+~~~
+# pcs status
+~~~
+
+FR Nous observons que les deux services sont désactivés au démarrage des
+FR serveurs et actuellement démarrés.
+FR
+We can see that both services are running and have been disabled at server
+startup.
+
+:::
+
+-----
+
+## Visualize the cluster state
+
+FR Pour visualiser l'état du cluster :
+FR
+FR * `crm_mon`: commande livrée avec Pacemaker
+FR * `pcs`
+FR
+To visualize the cluster state:
+
+* `crm_mon`: a command provided with Pacemaker
+* `pcs`
+
+::: notes
+
+FR L'outil `crm_mon` permet de visualiser l'état complet du cluster et des
+FR ressources. Voici le détail des arguments disponibles :
+FR
+FR * `-1`: affiche l'état du cluster et quitte
+FR * `-n`: regroupe les ressources par nœuds
+FR * `-r`: affiche les ressources non actives
+FR * `-f`: affiche le nombre fail count pour chaque ressource
+FR * `-t`: affiche les dates des événements
+FR * `-c`: affiche les tickets du cluster (utile pour les cluster étendus sur réseau WAN)
+FR * `-L`: affiche les contraintes de location négatives
+FR * `-A`: affiche les attributs des nœuds
+FR * `-R`: affiche plus de détails (node IDs, individual clone instances)
+FR * `-D`: cache l'entête
+FR
+FR Voici des exemples d'utilisation:
+FR
+The `crm_mon` tool is geared to the visualisation of the state of the cluster
+as a whole, including it's resources. Here is the detail of the available
+arguments:
+
+* `-1`: displays the state of the cluster and exits
+* `-n`: gathers resources on a per node basis
+* `-r`: displays the active resources
+* `-f`: displays the fail count for each node
+* `-t`: displays the dates of the events
+* `-c`: displays the tickets of the cluster (useful for extended clusters on WAN networks)
+* `-L`: displays the negative location constraints
+* `-A`: displays the node attributes
+* `-R`: displays mode detailed information (node IDs, individual clone instances)
+* `-D`: hide the header
+
+Here are some examples:
+
+~~~console
+# crm_mon -DnA
+# crm_mon -fronA
+# crm_mon -1frntcLAR
+~~~
+
+FR À noter que ces différents arguments peuvent être aussi activés ou désactivés
+FR dans le mode interactif.
+FR
+FR L'outil `pcs` contient quelques commandes utiles pour consulter l'état d'un
+FR cluster, mais n'a pas de mode interactif. Voici quelques exemples
+FR d'utilisation:
+FR
+
+Please note that these arguments can also be toggle on and off in interactive
+mode.
+
+The `pcs` tool comes equiped with several commands that are useful to display
+the cluster state, but it doesn't have an interactive mode. Here are few
+examples of their usage:
+
+~~~console
+# pcs cluster status
+# pcs status
+# pcs cluster cib
+# pcs constraint show
+~~~
+
+:::
+
+-----
+
+### Practical work: Cluster state visualization
+
+::: notes
+
+FR Expérimenter avec les commandes vues précédemment et leurs arguments.
+FR
+Experiment with the commands listed before and their arguments.
+
+:::
+
+-----
+
+# Corosync
+
+FR Rapide tour d'horizon sur Corosync.
+FR
+A Quick overview of Corosync.
+
+-----
+
+## Presentation
+
+FR * couche de communication bas niveau du cluster
+FR * créé en 2004
+FR * dérivé de OpenAIS
+FR * avec des morceaux de CMAN dedans ensuite (à vérifier)
+FR
+* communication layer of the clusterware
+* created in 2004
+* derived from OpenAIS
+* with some components from CMAN
+
+
+::: notes
+
+FR Corosync est un système de communication de groupe (`GCS`). Il fournit
+FR l'infrastructure nécessaire au fonctionnement du cluster en mettant à
+FR disposition des APIs permettant la communication et d'adhésion des membres au
+FR sein du cluster. Corosync fournit notamment des notifications de gain ou de
+FR perte du quorum qui sont utilisés pour mettre en place la haute disponibilité.
+FR
+Corosync is a group communication system (_GCS_). It provides the
+infrastructure necessary for the cluster to operate by providing API for
+communication and cluster membership. Among other features, it also provides
+notification for the gain or loss of quorum which is important to archive high
+availability.
+
+FR Son fichier de configuration se trouve à l'emplacement
+FR `/etc/corosync/corosync.conf`. En cas de modification manuelle, il faut
+FR __ABSOLUMENT__ veiller à conserver une configuration identique sur tous les
+FR nœuds. Cela peut être fait manuellement ou avec la commande `pcs cluster sync`.
+FR
+It's configuration is located in `/etc/corosync/corosync.conf`. In case of
+manual update, it is paramount to propagate the modifications on all nodes and
+ensure that all nodes have the same configuration. This can be done manually
+or with the command `pcs cluster sync`.
+
+FR La configuration de corosync est décrite dans la page de manuel
+FR `corosync.conf`. Ses fonctionnalités liées au quorum sont décrites dans le
+FR manuel nommé `votequorum`.
+FR
+The Corosync configuration is described in length in the man page for
+`corosync.conf`. The parameters describing quorum are described in the man page
+for `votequorum`.
+
+:::
+
+-----
+
+## Architecture
+
+FR * corosync expose ses fonctionnalités sous forme de services, eg. :
+FR * `cgp` : API de gestion de groupe de processus ;
+FR * `cmap` : API de gestion de configuration ;
+FR * `votequorum` : API de gestion du quorum.
+FR
+* corosync exposes it's functionnalities as servises, e.g.:
+ * `cpg` (closed process group): process group & membership management API;
+ * `cmap`: configuration management API;
+ * `votequorum`: quorum managment API.
+
+
+::: notes
+
+FR Corosync s'appuie sur une ensemble de services internes pour proposer plusieurs APIs aux applications
+FR qui l'utilisent.
+FR
+FR Corosync expose notamment l'api `cpg` dont l'objet est d'assurer le moyen de
+FR communication d'une applications distribuées. Cette api permet de gérer :
+FR
+FR * l'entrée et la sortie des membres dans un ou plusieurs groupes ;
+FR * la propagation des messages à l'ensemble des membres des groupes ;
+FR * la propagation des changements de configuration ;
+FR * l'ordre de délivrance des messages.
+FR
+Corosync relies on a set of internal services to propose several API to its
+client applications.
+
+One of those API is `cpg` whose role is to provide means of communication for
+distributed applications. This API can manage:
+
+* the entry or exit of members in one or more groups;
+* the propagation of messages to all members of said groups;
+* the propagation of configuration changes;
+* the order of delivery of messages.
+
+FR Corosync utilise `cmap` pour gérer et stocker sa configuration sous forme de stockage
+FR clé-valeur. Cette API est également mise à disposition des applications qui utilisent corosync.
+FR Pacemaker s'en sert notamment pour récupérer certaines informations sur le cluster et
+FR ses membres.
+FR
+Corosync uses `cmap` to manage and store it's configuration in the form of a
+key value store. This API is also available for the client applications of
+Corosync. For example, Pacemaker uses it to fetch some information from the
+cluster and it's members.
+
+FR Le service `votequorum` permet à corosync de fournir des notifications sur la gain ou la
+FR perte du quorum dans le cluster, le nombre de vote courant, etc.
+FR
+The `votequorum` service is designed to provide notification when quorum is
+archived or lost in the cluster, about the number of nodes in the cluster,
+etc.
+
+:::
+
+-----
+
+## Corosync 3 features
+
+FR Nouvelle librairie `kronosnet` (`knet`):
+FR
+FR * évolution du chiffrement
+FR * redondance des canaux de communications
+FR * compression
+FR
+
+New library `kronosnet` (`knet`):
+
+* cryptography
+* redundancy of channels
+* compression
+
+::: notes
+
+FR Corosync3 utilise la librairie kronosnet (`knet`). Cette libraire :
+FR
+FR * remplace les modes de transport `multicast` et `unicast` ;
+FR * remplace le protocole `RRP` (_Redundant Ring Protocole_).
+FR
+Corosync 3 uses the `kronosnet` (`knet`) library, which:
+
+* replaces the `multicast` and `unicast` method,
+* replaces the `RRP` protocol (_Redundant Ring Protocol_)
+
+FR Corosync implémente le protocole _Totem Single Ring Ordering and Membership_ pour la gestion
+FR des messages et des groupes. Il est possible de redonder les canaux de communications ou liens
+FR en créant plusieurs interfaces (option `totem` > `interface` > `linknumber`) qui seront
+FR utilisés comme support des rings (option `nodelist` > `node` > `ringX_addr`). `knet` permet
+FR de créer jusqu'à 8 liens avec des protocoles et des priorités différentes.
+FR
+FR Le chiffrement peut être configuré soit avec l'option `totem` > `secauth` soit avec les
+FR paramètres `totem` > `crypto_model`, `totem` > `crypto_cipher` et `totem` > `crypto_hash`.
+FR
+FR Il est également possible d'utiliser la compression.
+FR
+Corosync implements the _Totem Single Ring Ordering and Membership_ protocol
+for its message and group management. It's possible to add redundancy for
+communication channels and network links by creating several interfaces
+(`totem` > `interface` > `linknumer` option) which will be used by the rings
+(`nodelist` > `node` > `ringX_addr`). `knet` allows for the creation of
+up to 8 links with different protocols and priorities.
+
+Cryptography can be configured either with the option `totem` > `secauth` or
+the parameters `totem` > `crypto_model`, `totem` > `crypto_cipher` and `totem`
+> `crypto_hash`.
+
+It's also possible to use compression.
+
+:::
+
+-----
+
+## Two node clusters
+
+FR * paramètre dédié : `two_node: 1`
+FR * option héritée de CMAN
+FR * requiers `expected-votes: 2`
+FR * implique `wait_for_all: 1`
+FR * requiers un fencing hardware configuré sur la même interface que le heartbeat
+FR
+* dedicated parameter: `two_node: 1`
+* inherited from CMAN
+* requires: `expected-votes: 2`
+* implies: `wait_for_all: 1`
+* requiers a fencing hardware configured on the same interface as the
+ heartbeat.
+
+::: notes
+
+FR Considérons un cluster à deux nœuds avec un vote par nœud. Le nombre de vote
+FR attendu est 2 (`expected-votes`), il n'est donc pas possible d'avoir une
+FR majorité en cas de partition du cluster. La configuration `two_node` permet de
+FR fixer artificiellement le quorum à 1 et de résoudre ce problème.
+FR
+Given a two cluster node with one vote per node, the number of expected vote is
+2 (`expected-votes`). Therefore, it's not possible to have a majority in case
+of cluster partition. The `two_node` parameter fixes this problem by fixing the
+quorum at a value of 1.
+
+CR Ce paramétrage, implique `wait_for_all : 1` qui empêche le cluster d'établir
+CR une majorité tant que l'ensemble des nœuds n'est pas présent. Ce qui évite une
+CR partition au démarrage du cluster.
+CR
+This configuration implies the usage of `wait_for_all: 1`, which forbids the
+cluster from establishing a majority unless all members of the cluster are
+present. This restriction is designed to avoid a partition during cluster
+startup.
+
+CR En cas de partition réseau, les deux nœuds font la course pour fencer l'autre.
+CR Le nœud vainqueur conserve alors le quorum grâce au paramètre `two_node: 1`.
+CR Quand au second nœud, après redémarrage de Pacemaker, si la partition réseau
+CR existe toujours, ce dernier n'obtient donc pas le quorum grâce au paramètre
+CR `wait_for_all: 1` et en conséquence ne peut démarrer aucune ressource.
+CR
+In case of network partition, both nodes race to fence the other node. The
+winner keeps the quorum thanks to the parameter `two_node: 1`. If the second
+node is restarted while the partition is still present, it will not be able to
+archive the quorum thanks to the parameter `wait_for_all: 1`. As a result it
+will bot be able to start any ressource.
+
+FR Même si elle fonctionne, ce genre de configuration n'est cependant pas
+FR optimale. Comme en témoigne
+FR [cet article du blog de clusterlabs](http://blog.clusterlabs.org/blog/2018/two-node-problems).
+FR
+Even though this kind of configuration works, it's not optimal as explained in
+[this clusterlab blog
+post](http://blog.clusterlabs.org/blog/2018/two-node-problems).
+
+:::
+
+-----
+
+## Tools
+
+FR Corosync installe plusieurs outils:
+FR
+FR * `corosync-cfgtool` : administration, paramétrage
+FR * `corosync-cpgtool` : visualisation des différents groupes CPG
+FR * `corosync-cmapctl` : administration de la base d'objets
+FR * `corosync-quorumtool` : gestion du quorum
+FR
+Corosync installs several tools:
+
+* `corosync-cfgtool` : administration, configuration
+* `corosync-cpgtool` : cpg group visualization
+* `corosync-cmapctl` : administration of the cmap key value store
+* `corosync-quorumtool` : quorum managment
+
+
+::: notes
+
+FR `corosync-cfgtool` permet de :
+FR
+FR * arrêter corosync sur le serveur ;
+FR * récupérer l'IP d'un nœud ;
+FR * tuer un nœud ;
+FR * récupérer des informations sur les rings et réinitialiser leur statut ;
+FR * demander à l'ensemble des nœuds de recharger leur configuration.
+FR
+`corosync-cfgtool` can be used to:
+
+* stop corosync on the server;
+* retrieve the IP of a node;
+* kill a node;
+* retrieve information about rings and reinitialize their status;
+* ask all nodes to reload their configuration.
+
+FR `corosync-cpgtool` permet d'afficher les groupes cpg et leurs membres.
+FR
+`corosync-cpgtool` can be used to display cpg groups and members.
+
+FR `corosync-cmapctl` permet de manipuler et consulter la base d'objet de corosync,
+FR les actions possibles sont :
+FR
+FR * lister les valeurs associées aux clés : directement (ex: totem.secauth), par
+FR préfix(ex: totem.) ou sans filtre ;
+FR * définir ou supprimer des valeurs ;
+FR * changer la configuration depuis un fichier externe ;
+FR * suivre les modifications des clés stockées dans `cmap` en temps réel en filtrant
+FR sur un préfix ou directement sur un clé.
+FR
+`corosync-cmapctl` can be used to read and modify data in the key value store
+of corosync, possible actions are:
+
+* list the values for given keys: directrly (e.g.: totem.secauth), using a
+ prefix (e.g.: totem.) or without filters;
+* define or delete values;
+* change the configuration using an external file;
+* follow the modification of keys sorted in `cmap` in realtime.
+
+FR `corosync-quorumtool` permet d'accéder au service de quorum pour par exemple:
+FR
+FR * modifier la configuration des votes (nombre, nombre attendu) ;
+FR * suivre les modifications de quorum ;
+FR * lister les nœuds avec leurs nom, id et IPs .
+FR
+`corosync-quorumtool` can be used to access the quorum service in order to:
+
+* modify the configuration of votes (number & avaited number);
+* follow quorum evolution;
+* list nodes with their name, id and ips.
+
+:::
+
+-----
+
+## Practice work: Corosync utilisation
+
+::: notes
+
+FR 1. afficher le statut du ring local avec `corosync-cfgtool`
+FR 2. afficher l'IP de chaque nœud avec `corosync-cfgtool`
+FR 3. afficher les groupes CPG et leurs membres avec `corosync-cpgtool`
+FR 4. afficher la configuration des nœuds dans la base CMAP avec
+FR `corosync-cmapctl` (clé `nodelist`)
+FR 5. afficher l'état du quorum avec `corosync-quorumtool`
+FR
+1. display the local ring status with `corosync-cfgtool`
+2. display the IP of each node with `corosync-cfgtool`
+3. display CPG groups and members with `corosync-cpgtool`
+4. display the configuration of each node from the CMAP base with
+ `corosync-cmapctl` (key: `nodelist`)
+5. display the state of the quorum with `corosync-quorumtool`
+
+:::
+
+-----
+
+## Correction: Corosync utilisation
+
+::: notes
+
+FR 1. afficher le statut du ring local avec `corosync-cfgtool`
+FR
+1. display the local ring status with `corosync-cfgtool`
+
+~~~console
+# corosync-cfgtool -s
+Printing ring status.
+Local node ID 1
+RING ID 0
+ id = 10.20.30.6
+ status = ring 0 active with no faults
+~~~
+
+FR 2. afficher l'IP de chaque nœud avec `corosync-cfgtool`
+FR
+2. display the IP of each node with `corosync-cfgtool`
+
+~~~console
+# corosync-cfgtool -a 1
+10.20.30.6
+
+# corosync-cfgtool -a 2
+10.20.30.7
+
+# corosync-cfgtool -a 3
+10.20.30.8
+~~~
+
+FR 3. afficher les groupes CPG et leurs membres avec `corosync-cpgtool`
+FR
+3. display CPG groups and members with `corosync-cpgtool`
+
+~~~console
+# corosync-cpgtool -e
+Group Name PID Node ID
+crmd
+ 6912 1 (10.20.30.6)
+ 6647 3 (10.20.30.8)
+ 6727 2 (10.20.30.7)
+attrd
+ 6910 1 (10.20.30.6)
+ 6645 3 (10.20.30.8)
+ 6725 2 (10.20.30.7)
+stonith-ng
+ 6908 1 (10.20.30.6)
+ 6643 3 (10.20.30.8)
+ 6723 2 (10.20.30.7)
+cib
+ 6907 1 (10.20.30.6)
+ 6642 3 (10.20.30.8)
+ 6722 2 (10.20.30.7)
+pacemakerd
+ 6906 1 (10.20.30.6)
+ 6641 3 (10.20.30.8)
+ 6721 2 (10.20.30.7)
+~~~
+
+FR Chaque sous-processus de pacemaker est associé à un groupe de communication
+FR avec leur équivalents sur les autres nœuds du cluster.
+FR
+Each sub process of pacemaker is part of a communication group with it's
+counterpart on the other nodes.
+
+FR 4. afficher la configuration des nœuds dans la base CMAP avec
+FR `corosync-cmapctl` (clé `nodelist`)
+FR
+4. display the configuration of each node from the CMAP base with
+ `corosync-cmapctl` (key: `nodelist`)
+
+~~~console
+# corosync-cmapctl -b nodelist
+nodelist.local_node_pos (u32) = 0
+nodelist.node.0.nodeid (u32) = 1
+nodelist.node.0.ring0_addr (str) = hanode1
+nodelist.node.1.nodeid (u32) = 2
+nodelist.node.1.ring0_addr (str) = hanode2
+nodelist.node.2.nodeid (u32) = 3
+nodelist.node.2.ring0_addr (str) = hanode3
+~~~
+
+FR 5. afficher l'état du quorum avec `corosync-quorumtool`
+FR
+5. display the state of the quorum with `corosync-quorumtool`
+
+~~~console
+# corosync-quorumtool
+Quorum information
+------------------
+Date: ...
+Quorum provider: corosync_votequorum
+Nodes: 3
+Node ID: 1
+Ring ID: 3/8
+Quorate: Yes
+
+Votequorum information
+----------------------
+Expected votes: 3
+Highest expected: 3
+Total votes: 3
+Quorum: 2
+Flags: Quorate
+
+Membership information
+----------------------
+ Nodeid Votes Name
+ 3 1 hanode3
+ 2 1 hanode2
+ 1 1 hanode1 (local)
+~~~
+
+:::
+
+-----
+
+
+# Components of the cluster
+
+
+
+::: notes
+
+FR Dans ce chapitre, nous abordons rapidement l'architecture de Pacemaker en détaillant ses
+FR sous processus. Le but est de comprendre le rôle de chaque brique et ainsi mieux
+FR diagnostiquer l'état du cluster, son paramétrage et savoir interpréter les messages de
+FR log correctement. Voici les différents processus tel que démarrés par Pacemaker:
+FR
+In this chapter, we will do an overview of Pacemaker's architecture and focus
+on it's sub processes. The objective is to understand the role of each part in
+order to have an easier time diagnosing the cluster state, understanding it's
+configuration and interpreting the log messages correctly.
+
+~~~
+/usr/sbin/pacemakerd -f
+\_ /usr/libexec/pacemaker/cib
+\_ /usr/libexec/pacemaker/stonithd
+\_ /usr/libexec/pacemaker/lrmd
+\_ /usr/libexec/pacemaker/attrd
+\_ /usr/libexec/pacemaker/pengine
+\_ /usr/libexec/pacemaker/crmd
+~~~
+
+FR Le diagramme présente les différents éléments de Pacemaker au sein d'un cluster à trois
+FR nœuds. Une vue plus détaillée mais centrée sur un seul nœud est présenté dans la
+FR documentation de Pacemaker. Voir:
+FR
+FR [Schémas de l'architecture interne de Pacemaker](http://clusterlabs.org/pacemaker/doc/en-US/Pacemaker/2.0/html/Pacemaker_Explained/_pacemaker_architecture.html#_internal_components)
+FR
+This diagram shows the different components of Pacemaker in a three node
+cluster. A more detailed view, focused on a single node is present in
+Pacemaker's documentation. See:
+
+[Schemas of the internal architecture of Pacemaker](http://clusterlabs.org/pacemaker/doc/en-US/Pacemaker/2.0/html/Pacemaker_Explained/_pacemaker_architecture.html#_internal_components)
+
+FR Cette architecture et le paramétrage de Pacemaker permet de supporter différents types de
+FR scénario de cluster dont certains (vieux) exemples sont présentés dans le wiki de
+FR Pacemaker:
+FR
+FR [Schémas des différentes configuration de nœuds possibles avec Pacemaker](https://wiki.clusterlabs.org/wiki/Pacemaker#Example_Configurations)
+FR
+This architecture is designed to support different types of clusters. Some
+(old) example are present in the Pacemaker wiki:
+
+[Schemas of different cluster configuration in pacemaker](https://wiki.clusterlabs.org/wiki/Pacemaker#Example_Configurations)
+
+:::
+
+
+-----
+
+## Cluster Information Base (CIB)
+
+FR * détient la configuration du cluster
+FR * l'état des différentes ressources
+FR * un historique des actions exécutées
+FR * stockage fichier au format XML
+FR * synchronisé automatiquement entre les nœuds
+FR * historisé
+FR * géré par le processus `cib`
+FR * renommé `pacemaker-based` depuis la version 2.0
+FR
+* contains:
+ - the cluster configuration
+ - the state of the resources
+ - an history of the latest actions
+* stored in XML format
+* automatically synchronized between nodes
+* archived
+* managed by the `cib` process
+ - renamed `pacemaker-based` since version 2.0
+
+::: notes
+
+FR La CIB est la représentation interne de la configuration et de l'état des composantes du
+FR cluster. C'est un fichier XML, créée par Pacemaker à l'initialisation du cluster et qui
+FR évolue ensuite au fil des configurations et évènements du cluster.
+FR
+The CIB is a internal representation of the configuration and state of the
+cluster's components and resources. It's an XML file, created by Pacemaker
+during cluster initialization. It evolves as the cluster configuration changes
+and events takes place in the cluster.
+
+FR En fonction de cet ensemble d'états et du paramétrage fourni, le cluster détermine l'état
+FR idéal de chaque ressource qu'il gère (démarré/arrêté/promu et sur quel serveur) et
+FR calcule les transitions permettant d'atteindre cet état.
+FR
+From the component states and configuration, the cluster determines the ideal
+state for each managed resource (started/stopped/promoted and on which server)
+and computes the transitions necessary to reach this state.
+
+FR Le processus `cib` est chargé d'appliquer les modifications dans la CIB, de
+FR conserver les information transitoires en mémoire (statuts, certains scores, etc) et de
+FR notifier les autres processus de ces modifications si nécessaire.
+FR
+The `cib` process (`pacemaker-based`) is tasked to apply the modification
+inside the CIB, keep track of transient information (status, some scores, etc.)
+ad notify the other processes of the changes if it's necessary.
+
+FR Le contenu de la CIB est historisé puis systématiquement synchronisé entre les nœuds à
+FR chaque modification. Ces fichiers sont stockés dans `/var/lib/pacemaker/cib` :
+FR
+The content of the CIB is archived and synchronized between all nodes after
+each modification. These files are stored in `/var/lib/pacemaker/cib`.
+
+~~~
+ls /var/lib/pacemaker/cib/ -alh
+total 68K
+drwxr-x--- 2 hacluster haclient 4.0K Feb 7 16:46 .
+drwxr-x--- 6 hacluster haclient 4.0K Feb 7 12:16 ..
+-rw------- 1 hacluster haclient 258 Feb 7 16:43 cib-1.raw
+-rw------- 1 hacluster haclient 32 Feb 7 16:43 cib-1.raw.sig
+-rw------- 1 hacluster haclient 442 Feb 7 16:43 cib-2.raw
+-rw------- 1 hacluster haclient 32 Feb 7 16:43 cib-2.raw.sig
+-rw------- 1 hacluster haclient 639 Feb 7 16:43 cib-3.raw
+-rw------- 1 hacluster haclient 32 Feb 7 16:43 cib-3.raw.sig
+-rw------- 1 hacluster haclient 959 Feb 7 16:43 cib-4.raw
+-rw------- 1 hacluster haclient 32 Feb 7 16:43 cib-4.raw.sig
+-rw------- 1 hacluster haclient 959 Feb 7 16:43 cib-5.raw
+-rw------- 1 hacluster haclient 32 Feb 7 16:43 cib-5.raw.sig
+-rw------- 1 hacluster haclient 959 Feb 7 16:46 cib-6.raw
+-rw------- 1 hacluster haclient 32 Feb 7 16:46 cib-6.raw.sig
+-rw-r----- 1 hacluster haclient 1 Feb 7 16:46 cib.last
+-rw------- 1 hacluster haclient 959 Feb 7 16:46 cib.xml
+-rw------- 1 hacluster haclient 32 Feb 7 16:46 cib.xml.sig
+~~~
+
+FR `cib.xml` correspond à la version courante de la CIB, les autres fichiers `cib-*.raw`,
+FR aux versions précédentes.
+FR
+`cib.xml` is the current version of the CIB, the `cib-*.raw` files are older
+versions of it.
+
+FR Par défaut, Pacemaker conserve toutes les versions de la CIB depuis la création du
+FR cluster. Il est recommandé de limiter ce nombre de fichier grâce aux paramètres
+FR `pe-error-series-max`, `pe-warn-series-max` et `pe-input-series-max`.
+FR
+By default, Pacemaker keep all the versions of the CIB since cluster creation.
+It's advised to limit the amount of files kept with the parameters:
+`pe-error-series-max`, `pe-warn-series-max` and `pe-input-series-max`.
+
+FR Il n'est pas recommandé d'éditer la CIB directement en XML. Préférez toujours utiliser
+FR les commandes de haut niveau proposées par `pcs` ou `crm`. En dernier recours, utilisez
+FR l'outil `cibadmin`.
+FR
+Making modification by editing the CIB directly is not recommanded. A better
+practice is to used the high level commands available in `pcs` or `crm`. As a
+last resort, the `cibadmin` tool is available.
+
+:::
+
+-----
+
+### Practice work: CIB
+
+::: notes
+
+FR 1. consulter le contenu de ce répertoire où est stockée la CIB
+FR 2. identifier la dernière version de la CIB
+FR 3. comparer avec `cibadmin --query` et `pcs cluster cib`
+FR
+1. check the content of the directory where the CIB is stored
+2. identify the last version of the CIB
+3. compare the output of the commands `cibadmin --query` and `pcs cluster cib`
+
+:::
+
+-----
+
+### Correction: CIB
+
+::: notes
+
+FR 1. consulter le contenu de ce répertoire où est stockée la CIB
+FR
+1. check the content of the directory where the CIB is stored
+
+~~~
+# ls /var/lib/pacemaker/cib
+~~~
+
+FR 2. identifier la dernière version de la CIB
+FR
+FR La version courante de la CIB est stockée dans
+FR `/var/lib/pacemaker/cib/cib.xml`. Sa version est stockée dans
+FR `/var/lib/pacemaker/cib/cib.last`.
+FR
+2. identify the last version of the CIB
+
+The current version of the CIB is stored in `/var/lib/pacemaker/cib/cib.xml`.
+It's version is stored in `/var/lib/pacemaker/cib/cib.last`.
+
+FR 3. comparer avec `cibadmin --query` et `pcs cluster cib`
+FR
+FR Vous observez une section `` supplémentaire dans le document
+FR XML présenté par `cibadmin`. Cette section contient l'état du cluster et est
+FR uniquement conservée en mémoire.
+FR
+
+3. compare the output of the commands `cibadmin --query` and `pcs cluster cib`
+
+There is a additional `` section in the XML document presented by
+`cibadmin`. This section contains the cluster state and is only kept in
+memory which explains why it's onlu visible with `cibadmin`.
+
+:::
+
+-----
+
+### Designated Controler (DC) - Global diagram
+
+
+
+-----
+
+## Designated Controler (DC)
+
+FR * daemon `CRMd` désigné pilote principal sur un nœud uniquement
+FR * lit et écrit dans la CIB
+FR * invoque PEngine pour générer les éventuelles transitions
+FR * contrôle le déroulement des transitions
+FR * envoie les actions à réaliser aux daemons `CRMd` des autres nœuds
+FR * possède les journaux applicatifs les plus complets
+FR
+
+* a `CRMd` daemon appointed as the manager of the cluster
+ - present only on one node
+* read and write from/to the CIB
+* calls the PEngine to generate the necessary transitions
+* control the proceeding of transitions
+* sends the actions to the daemons`CRMd` of other nodes
+* has the most complete traces of all nodes
+
+::: notes
+
+FR Le *Designated Controler* est élu au sein du cluster une fois le groupe de communication
+FR établi au niveau de Corosync. Il pilote l'ensemble du cluster.
+FR
+FR Il est responsable de:
+FR
+FR * lire l'état courant dans la CIB
+FR * invoquer le `PEngine` en cas d'écart avec l'état
+FR stable (changement d'état d'un service, changement de configuration, évolution des
+FR scores ou des attributs, etc)
+FR * mettre à jour la CIB (mises à jour propagée aux autres nœuds)
+FR * transmettre aux `CRMd` distants une à une les actions à réaliser sur leur nœud
+FR
+FR C'est le DC qui maintient l'état primaire de la CIB ("master copy").
+FR
+
+
+The *Designated Controler* is elected once a communication group is established
+by Corosync. It manages the whole cluster.
+
+It's responsible for:
+
+* reading the current state in the CIB
+* invoking the `PEngine` if the state of the cluster is different from it's
+ expected state (service state change, configuration change, evolution of
+ scores or attributes, etc.)
+* updates the CIB (the updates sent to all nodes)
+* dictate the actions that have to be executed to the relevant remote `CRMd`
+ processes, theses changes are send one at a time
+
+The DC is responsible for the _master copy_ of the CIB.
+
+
+:::
+
+-----
+
+### PEngine - Global Diagram
+
+
+
+-----
+
+## Policy Engine (PEngine)
+
+FR * reçoit en entrée les informations d'état des ressources et le paramétrage
+FR * décide de l'état idéal du cluster
+FR * génère un graphe de transition pour atteindre cet état
+FR * renommé `Scheduler` depuis la version 2.0
+FR * peut être consulté grâce à la commande `crm_simulate`
+FR
+FR 
+
+* receives information about the state of resources and configuration
+* decides the ideal state for the cluster
+* creates a transition graph to reach the ideal state
+* renamed `Scheduler` in version 2.0
+* can be leveraged with the `crm_simulate` command
+
+
+
+::: notes
+
+FR Le `PEngine` est la brique de Pacemaker qui calcule les transitions nécessaires pour
+FR passer d'un état à l'autre.
+FR
+FR Il reçoit en entrée des informations d'état et de paramétrage au format XML (extrait de
+FR la CIB), détermine si un nouvel état est disponible pour les ressources du cluster, et
+FR calcule toutes les actions à mettre en œuvre pour l'atteindre.
+FR
+FR Toutes ces actions sont regroupées au sein d'un graph de transition que le
+FR `Designated Controller`, qui pilote le cluster, devra ensuite mettre en œuvre.
+FR
+The `PEngine` is the Pacemaker component responsible for the computation of the
+transition necessary to go from one state to another.
+
+It receives information about states and configuration in XML format (from the
+CIB), decides if a new state is available and computes all the actions
+necessary to reach it.
+
+All theses actions are gathered in a transition graph which will be applied by
+the component responsible for decision making: the `Designated Controller`.
+
+FR Voici un exemple de transition complexe présentant une bascule maître-esclave DRBD:
+FR 
+FR
+FR Ce diagramme vient de la documentation de Pacemaker. L'original est disponible à cette
+FR adresse:
+FR
+FR
+FR Les explications sur les codes couleurs sont disponibles à cette adresse:
+FR
+FR
+This is an example of complex transition graph involving a master slave DRBD
+switchover.
+
+
+This diagram comes from the Pacemaker documentation. The original is available
+at:
+
+
+The explanation of the color code is available at this address:
+
+
+FR Dans cet exemple chaque flèche impose une dépendance et un ordre entre les actions. Pour
+FR qu'une action soit déclenchée, toutes les actions précédentes doivent être exécutées et
+FR réussies. Les textes en jaune sont des "actions virtuelles", simples points de passage
+FR permettant de synchroniser les actions entre elles avant de poursuivre les suivantes. Les
+FR textes en noir représentent des actions à exécuter sur l'un des nœuds du cluster.
+FR
+FR Le format des textes est le suivant: `__`
+FR
+FR Une action avec un intervalle à 0 est une action ponctuelle (`start`, `stop`, etc). Une
+FR action avec un intervalle supérieur à 0 est une action récurrente, tel que `monitor`.
+FR
+In this example each arrow represents a dependancy and forces an order of
+execution between actions. In an order for an action to be triggered, all the
+preceding actions must have been executed and have succeded. The yellow texts
+represent virtual actions, they act as synchronisation points when several
+actions are required before starting another one. The black texts represent
+actions that must be executed on a cluster node.
+
+The format of the text is the following: `__`.
+
+An action with an interval of zero is a one off action (`start`, `stop`, etc.).
+Actions with intervals superior to zero are recurring action such as `monitor`.
+
+FR Dans cet exemple:
+FR
+FR * les actions 1 à 4 concernent l'exécution des actions `notify pre-demote` sur les nœuds
+FR "frigg" et "odin" du cluster
+FR * l'action 1 déclenche en parallèle les deux actions 2 et 3
+FR * l'action 4 est réalisée une fois que les actions 1, 2 et 3 sont validées
+FR * l'action 5 est exécutée n'importe quand
+FR * l'action 5 interrompt l'exécution récurrente de l'action `monitor` sur la ressource
+FR "drbd0:0" du serveur "frigg"
+FR * l'action 7 est exécutée après que 5 et 6 soient validées
+FR * l'action 7 effectue un `demote` de la ressource "drbd0:0" sur "frigg" (qui n'est donc
+FR plus supervisée)
+FR * la pseudo action 8 est réalisée une fois que l'action `demote` est terminée
+FR * la pseudo action 9 initialise le déclenchement des actions `notify post-demote` et
+FR dépend de la réalisation précédente de la notification "pre-demote" et de l'action
+FR `demote` elle même
+FR * les actions 9 à 12 représentent l'exécution des notifications `post-demote` dans tout
+FR le cluster
+FR * les actions 13 à 24 représentent les actions de `notify pre-promote`, `promote` de
+FR drbd sur "odin" et `notify post-promote` au sein du cluster
+FR * les actions 25 et 27 peuvent alors être exécutées et redémarrent les actions de
+FR monitoring récurrentes de drbd sur "odin" et "frigg"
+FR * les actions 26, 28 à 30 démarrent un groupe de ressource dépendant de la ressource
+FR drbd
+FR
+In this example:
+
+* action 1 to 4 are `notify pre-demote` actions executed on the nodes "frigg"
+ and "odin"
+ - action 1 is used to start action 2 and 3 in parallel
+ - action 4 is done after action 1, 2 and 3 are completed sucessfully
+* action 5 is executed at any time
+* action 5 cancels the recurring execution of the `monitor` action on ressource
+ "drbd0:0" of server "frigg"
+* action 7 is executed after action 5 and 6 are deemed valid
+* action 7 `demotes` the ressource "drbd0:0" on server "frigg" (it is therefore
+ no longer monitored)
+* action 8 is a pseudo action triggered once the `demote` is finished
+* action 9 is a pseudo action responsible for starting the the two `notify
+ post-demote` actions. It requires the `pre-demote` notification and the
+ `demote` action
+* action 9 to 12 represent the execution of the `post-demote` actions in the
+ whole cluster
+* action 13 to 24 represent the execution of the `notify-pre-demote` and
+ `demote` action on the drbd resource of "odin". `notify post-demote` is a
+ cluster wide action
+* action 25 to 27 can then be executed and restart the recurring monitoring
+ actions of drbd on "odin" and "frigg"
+* action 26, 28 and 29 start the group of resource which depends on the drbd
+ resource
+
+
+FR Enfin, il est possible de consulter les transitions proposées par le PEngine
+FR grâce à la commande `crm_simulate`. Cette commande est aussi parfois utile
+FR pour en extraire des informations disponibles nulles par ailleurs, comme les
+FR [scores de localisation][Contraintes de localisation].
+FR
+Finally, it's possible to check the transitions proposed by PEngine with the
+command `crm_simulate`. This command is also sometimes useful to get
+information that are not accessible elsewhere like the [location
+scores][Localisation constraints].
+
+:::
+
+-----
+
+### Practical work: PEngine
+
+::: notes
+
+FR 1. identifier sur quels nœuds est lancé le processus `pengine`
+FR 2. identifier où se trouvent les logs de `pengine`
+FR 3. identifier le DC
+FR 4. observer la différence de contenu des log de `pengine` entre nœuds
+FR 5. afficher la vision de PEngine sur l'état du cluster (`crm_simulate`)
+FR
+1. identify on which node the processus `pengine` is started.
+2. identify where are the logs of the `pengine`
+3. identify the DC
+4. check the difference between the content of the `pengine` logs across nodes
+5. display the PEngine point of view of the cluster state (`¢rm_simulate`)
+
+:::
+
+-----
+
+### Correction: PEngine
+
+::: notes
+
+FR 1. identifier sur quels nœuds est lancé le processus `pengine`
+FR
+FR Sur tous les nœuds.
+FR
+1. identify on which node the processus `pengine` is started.
+
+On all nodes
+
+FR 2. identifier où se trouvent les logs de `pengine`
+FR
+FR Les messages de `pengine` se situent dans `/var/log/cluster/corosync.log`,
+FR mélangés avec ceux des autres sous processus.
+FR
+FR Il est aussi possible de les retrouver dans `/var/log/messages` ou ailleurs en
+FR fonction de la configuration de corosync, syslog, etc.
+FR
+2. identify where are the logs of the `pengine`
+
+The `pengine` logs is located in `/var/log/cluster/corosync.log`, it's mixed
+with the other processus logs.
+
+It's also possible to find these messages in `/var/log/messages` or wherever
+the configuration of corosync, syslog, etc. dictates it.
+
+FR 3. identifier le DC
+FR
+FR Utiliser `crm_mon`, `pcs status` ou `crmadmin`:
+FR
+3. identify the DC
+
+Use `crm_mon`, `pcs status` or `crmadmin`:
+
+~~~console
+# crmadmin -D
+Designated Controller is: hanode3
+~~~
+
+FR 4. observer la différence de contenu des log de `pengine` entre nœuds
+FR
+FR Seuls le DC possède les messages relatifs au calcul de transitions effectués
+FR par le sous-processus `pengine`.
+FR
+4. check the difference between the content of the `pengine` logs across nodes
+
+The message related to the transition calculation done by the `pengine` sub
+process are only available on the DC.
+
+FR 5. afficher la vision de PEngine sur l'état du cluster (`crm_simulate`)
+FR
+5. display the PEngine point of view of the cluster state (`¢rm_simulate`)
+
+~~~console
+# crm_simulate --live-check
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+~~~
+
+:::
+
+-----
+
+### Cluster Resource Manager (CRM) - Global diagram
+
+
+
+-----
+
+## Cluster Resource Manager (CRM)
+
+FR * daemon `CRMd` local à chaque nœud
+FR * chargé du pilotage des événements
+FR * reçoit des instructions du `PEngine` s'il est DC ou du `CRMd` DC distant
+FR * transmet les actions à réaliser au sein des transitions
+FR * au daemon `LRMd` local
+FR * au daemon `STONITHd` local
+FR * récupère les codes retours des actions
+FR * transmets les codes retours de chaque action au `CRMd` DC
+FR * renommé `controller` depuis la version 2.0
+FR
+* local daemon `CRMd` on each node
+* tasked with event management
+* receives instructions from `PEngine` if it's the DC or from a remote `CRMd`
+ otherwise (the DC)
+* transmits the actions
+ * to the local `LRMd` daemon
+ * to the local `STONITHd` daemon
+* fetches the return code of the actions
+* resends these return code to `CRMDd` on the DC
+* renamed `controller` in version 2.0
+
+::: notes
+
+
+FR Le daemon `CRMd` est local à chaque nœud qui pilote les événements. Il peut soit être
+FR actif (DC), et donc être chargé de l'ensemble du pilotage du cluster, soit passif, et
+FR attendre que le `CRMd` DC lui fournisse des instructions.
+FR
+FR Lorsque des instructions lui sont transmises, il les communique aux daemons `LRMd` et/ou
+FR `STONITHd` locaux pour qu'ils exécutent les actions appropriées auprès des _ressources
+FR agents_ et _fencing agents_.
+FR
+FR Une fois l'action réalisée, le `CRMd` récupère le statut de l'action (via
+FR son code retour) et le transmet au `CRMd` DC qui en valide la cohérence
+FR avec ce qui est attendu au sein de la transition.
+FR
+FR En cas de code retour différent de celui attendu, le `CRMd` DC décide d'annuler la
+FR transition en cours. Il demande alors une nouvelle transition au `PEngine`.
+FR
+The `CRMd` daemon is local to each nodes and manages events. It can be active
+(DC) in which case it's in charge of managing the whole cluster, or passive in
+which case it recieves instructions from the `CRMd` DC.
+
+When instructions are fed to `CRMd`, it communicates with the local `LRMd`
+and/or local `STONITHd` so that the appropriate actions can be executed by
+the _resource agents_ and _fencing agents_.
+
+Once the action is finished, `CRMd` fetches the status of the action (via the
+return code) and transmits it to the `CRMd` DC. The DC validates the coherence
+of the result with what was expected in the transition.
+
+If the return code is different from the expected one, the `CRMd` DC decides to
+cancel the current transaction and asks for a new transition from the
+`PEngine`.
+
+:::
+
+-----
+
+### Practical work: Cluster Resource Manager
+
+::: notes
+
+FR 1. trouver comment sont désignés les messages du `CRMd` dans les log
+FR 2. identifier dans les log qui est le DC
+FR
+1. find how the `CRMd` messages are tagged in the logs
+2. identify which server is the DC in the logs
+
+:::
+
+-----
+
+### Correction: Cluster Resource Manager
+
+Study of the `CRMd` daemon.
+
+::: notes
+
+FR 1. trouver comment sont désignés les messages du `CRMd` dans les log
+FR
+FR Les messages de ce sous-processus sont identifiés par `crmd:`.
+FR
+1. find how the `CRMd` messages are tagged in the logs
+
+The messages from this sub process are identified with `crmd:`
+
+FR 2. identifier dans les log qui est le DC
+FR
+2. identify which server is the DC in the logs
+~~~
+crmd: info: update_dc: Set DC to hanode1 (3.0.14)
+~~~
+
+FR À noter que le retrait d'un DC est aussi visible:
+FR
+When a DC is demoted, it's also visible:
+
+~~~
+crmd: info: update_dc: Unset DC. Was hanode2
+~~~
+
+:::
+
+-----
+
+## `STONITHd` and _Fencing Agent_
+
+
+
+-----
+
+### `STONITHd`
+
+
+FR * daemon `STONITHd`
+FR * gestionnaire des agents de fencing (_FA_)
+FR * utilise l'API des fencing agent pour exécuter les actions demandées
+FR * reçoit des commandes du `CRMd` et les passe aux _FA_
+FR * renvoie le code de retour de l'action au `CRMd`
+FR * support de plusieurs niveau de fencing avec ordre de priorité
+FR * outil `stonith-admin`
+FR * renommé `fenced` depuis la version 2.0
+FR
+* `STONITHd` daemon
+* fencing agent manager (_FA_)
+* uses the fencing agent API to execute the requiered actions
+* recieves the commands from `CRMd` and feeds them to the _FA_
+* resends the return code of the actions to `CRMd`
+* supports several level of fencing with a priority order
+* `stonith-admin` tool
+* renamed `fencer` since version 2.0
+
+::: notes
+
+
+
+FR Le daemon `STONITHd` joue sensiblement un rôle identique à celui du `LRMd` vis-à-vis des
+FR agents de fencing (_FA_).
+
+FR
+FR L'outil `stonith-admin` permet d'interagir avec le daemon `STONITHd`, notamment:
+FR
+FR * `stonith_admin -V --list-registered` : liste les agents configurés
+FR * `stonith_admin -V --list-installed` : liste tous les agents disponibles
+FR * `stonith_admin -V -l ` : liste les agents contrôlant le nœud spécifié.
+FR * `stonith_admin -V -Q ` : contrôle l'état d'un nœud.
+FR
+The `STONITHd` daemon is for the fencing agents (_FA_) what `LRMd` is for
+resource agents (_RA_).
+
+The `stonith-admin` tool can be used to interact with the `STONITHd` daemon,
+for example:
+
+* `stonith_admin -V --list-registered` : list the configured agents
+* `stonith_admin -V --list-installed` : list the available agents
+* `stonith_admin -V -l ` : list the agents that can terminate the
+ specified node
+* `stonith_admin -V -Q ` : controls the state of a device on a node
+
+:::
+
+-----
+
+### _Fencing Agent_ (_FA_)
+
+FR * script permettant de traduire les instructions du _fencer_ vers l'outil de fencing
+FR * doit assurer que le nœud cible est bien complètement isolé du cluster
+FR * doit renvoyer des codes retours définis dans l'API des _FA_ en fonction des résultats
+FR * dix actions disponibles dans l'API, toutes ne sont pas obligatoires
+FR
+* script designed to translate `fencer`'s instruction to the fencing device
+* must guaranty that the target node is isolated from the reste of the cluster
+* must return the approriate return codes as defined in the fencing agent API
+* ten actions are availagble in the API, the are not all mandatory
+
+::: notes
+
+FR Attention aux _FA_ qui dépendent du nœud cible !
+FR
+FR Exemple classique : la carte IPMI. Si le serveur a une coupure électrique le
+FR _FA_ (la carte IPMI donc) n'est plus joignable. Pacemaker ne reçoit donc
+FR aucune réponse et ne peut pas savoir si le fencing a fonctionné, ce qui
+FR empêche toute bascule.
+FR
+FR Il est conseillé de chaîner plusieurs _FA_ si la méthode de fencing présente
+FR un _SPoF_: IPMI, rack d'alimentation, switch réseau ou SAN, ...
+FR
+Be wary of _FA_ that depend on the node state !
+
+
+Example: the IPMI card. If the server as an electrical outage, the _FA_ (the
+IPMI card) is no longer reachable. Pacemaker can't receive feedback from it
+therefore it cannot know if the fencing was successful, which can prevent a
+failover.
+
+In such cases, where the fencing is a _SPoF_ (IMPI, rack power supply, network
+switch or SAN ..), it's a good practice to chaine several _FA_.
+
+
+FR Voici les actions disponibles de l'API des FA:
+FR
+FR * `off`: implémentation obligatoire. Permet d'isoler la ressource ou le serveur
+FR * `on`: libère la ressource ou démarre le serveur
+FR * `reboot`: isoler et libérer la ressource. Si non implémentée, le daemon
+FR exécute les actions off et on.
+FR * `status`: permet de vérifier la disponibilité de l'agent de fencing et le
+FR statut du dispositif concerné: on ou off
+FR * `monitor`: permet de vérifier la disponibilité de l'agent de fencing
+FR * `list`: permet de vérifier la disponibilité de l'agent de fencing et de
+FR lister l'ensemble des dispositifs que l'agent est capable d'isoler (cas d'un
+FR hyperviseur, d'un PDU, etc)
+FR * `list-status`: comme l'action `list`, mais ajoute le statut de chaque dispositif
+FR * `validate-all`: valide la configuration de la ressource
+FR * `meta-data`: présente les capacités de l'agent au cluster
+FR * `manpage`: nom de la page de manuelle de l'agent de fencing
+FR
+
+The following action are available in the _FA_ API:
+
+* `off`: mandatory action, enables the isolation of a resource of server
+* `on`: frees a resource or start a server
+* `reboot`: isolate and restart a resource. If the action is not available the
+ daemon will execute the off and on actions
+* `status`: check to see if a local stonith device's port is reachable
+* `monitor`: check to see if a local stonith device is reachable
+* `list`: listing hosts and port assignments from a local stonith device and
+ the fencing agent availability
+* `list-status`: same as `list` but with the status of each assignement
+* `validate-all`: validate the configuration of the resource
+* `meta-data`: displays the capabilities of the agent for the cluster
+* `manpage`: displays the name of the man page for this fencing agent
+
+:::
+
+-----
+
+### Practical work: Fencing
+
+::: notes
+
+FR Au cours de workshop, nous utilisons l'agent de fencing `fence_virsh`. Il ne
+FR fait pas parti des agents de fencing distribués par défaut et s'installe via le
+FR paquet `fence-agents-virsh`. Cet agent de fencing est basé sur SSH et la
+FR commande `virsh`.
+FR
+FR 1. installer tous les _FA_ ainsi que `fence_virsh`
+FR 2. lister les FA à l'aide de `pcs resource` ou `stonith_admin`
+FR
+FR Nous abordons la création d'une ressource de fencing plus loin dans le workshop.
+FR
+During this worshop, we will use the fencing agent `fence_virsh`. it's not part
+of the default fencing agent package and can be installed via the package
+`fence-agent-virsh`. This fencing agent is based on SSH and the `virsh`
+command.
+
+1. install all the _FA_ including `fence_virsh`
+2. list the _FA_ with `pcs resource` and `stonith_admin`
+
+We will delve into fencing resource creation later on.
+
+:::
+
+-----
+
+### Correction: Fencing
+
+::: notes
+
+FR 1. installer tous les _FA_ ainsi que `fence_virsh`
+FR
+1. install all the _FA_ including `fence_virsh`
+
+~~~console
+# yum install -y fence-agents-all fence-agents-virsh
+~~~
+
+FR 2. lister les FA à l'aide de `pcs resource` ou `stonith_admin`
+FR
+2. list the _FA_ with `pcs resource` and `stonith_admin`
+
+~~~
+# pcs resource agents stonith
+fence_amt_ws
+fence_apc
+fence_apc_snmp
+[...]
+
+# stonith_admin --list-installed
+ fence_xvm
+ fence_wti
+ fence_vmware_soap
+[...]
+~~~
+
+:::
+
+-----
+
+## `LRMd` et _Resources Agent_ - Global diagram
+
+
+
+-----
+
+### Local Resource Manager (LRM)
+
+FR * daemon `lrmd`
+FR * interface entre le `CRMd` et les _resource agents_ (_RA_)
+FR * capable d'exécuter les différents types de _RA_ supportés (OCF, systemd,
+FR LSF, etc) et d'en comprendre la réponse
+FR * reçoit des commandes du `CRMd` et les passe aux _RA_
+FR * renvoie le résultat de l'action au `CRMd` de façon homogène, quelque
+FR soit le type de _RA_ utilisé
+FR * est responsable d'exécuter les actions récurrentes en toute autonomie et de
+FR prévenir le `CRMd` en cas d'écart avec le résultat attendu
+FR * renommé _local executor_ depuis la version 2.0
+FR
+* `LRMd` daemon
+* interface between `CRMd` and the _resource agent_ (_RA_)
+* can inteface with all the available _RA_ types (OCF, systemd, LSF, etc.) and
+ understand their answers
+* receives `CRMd` commands and feeds them to _RA_
+* resends the result of the action to `CRMd` in a homogenous fashion despite
+ the _RA_ type
+* is responsible for the execution of recurring actions and must warn `CRMd` in
+ case the result of the action is different from the expected one (e.g.
+ monitor)
+* renamed 'local executor' in version 2.0
+
+::: notes
+
+
+FR Lorsqu'une instruction doit être transmise à un agent, le `CRMd` passe
+FR cette information au `LRMd`, qui se charge de faire exécuter l'action
+FR appropriée par le _RA_.
+FR
+FR Le daemon `LRMd` reçoit un code de retour de l'agent, qu'il transmet au
+FR `CRMd`, lequel mettra à jour la CIB pour que cette information soit
+FR partagée au niveau du cluster.
+FR
+FR Pour les actions dont le paramètre `interval` est supérieur à 0, le
+FR `LRMd` est responsable d'exécuter les actions de façon récurrente
+FR à la période indiquée dans la configuration. Le `LRMd` ne
+FR reviendra vers le `CRMd` que si le code retour de l'action varie.
+FR
+When an instruction must be sent to an agent, `CRMd` sends the information to
+`LRMd` which execute the appropriate action on the _RA_.
+
+The `LRMd` daemon receives the return code from the agent and transmits it to
+`CRMd` which is tasked with updating the CIB so that the whole cluster is aware
+of the result.
+
+For action where the `interval` parameter is superior to 0, `LRMd` is
+responsible for their recurring execution once the period specified in the
+configuration has ended. `LRMd` will get back to `CRMd` in case the return code
+is not the expected one.
+
+:::
+
+-----
+
+### _Ressource Agent_ (_RA_)
+
+FR * applique les instructions du `LRMd` sur la ressource qu'il gère
+FR * renvoie des codes retours stricts reflétant le statut de sa ressource
+FR * plusieurs types/API de _ressource agent_ supportés
+FR * la spécification "OCF" est la plus complète
+FR * l'API OCF présente au `CRMd` les actions supportées par l'agent
+FR * `action` et `operation` sont deux termes synonymes
+FR * chaque opérations a un timeout propre et éventuellement une récurrence
+FR
+* applies the instruction sent by `LRMd` on the resource it manages
+* resends the return code according to the API specification, in accordance to
+ the resource status
+* several kinds of _resource agent_ supported (with different API)
+* the _OCF_ specification is the most exhaustive
+* the _OCF_ API present the action supported by the agent to `CRMd`
+* `action` and `operation` as synonyms
+* each operation has a specific timeout and might have an inteval for recuring
+ operations
+
+::: notes
+
+FR Il est possible d'utiliser plusieurs types de _RA_ différents au sein d'un même cluster:
+FR
+FR * OCF (Open Cluster Framework, type préconisé)
+FR * SYSV
+FR * systemd...
+FR
+FR Vous trouverez la liste des types supportés à l'adresse suivante:
+FR
+It's possible to use several kinfs of _RA_ in the same cluster:
+
+* OCF (Open ClusterFramework, the advised type)
+* SYSV
+* Systemd
+* etc..
+
+A list of all available types of _RA_ is available here:
+
+
+FR Dans les spécifications du type OCF, un agent a le choix parmi dix codes retours
+FR différents pour communiquer l'état de son opération à `LRMd`:
+FR
+
+In the _OCF_ specification, ten different return codes are available for the
+_RA_ to communicate the state of the action it was tasked with by `LMRd`.
+
+* `OCF_SUCCESS` (0, soft)
+* `OCF_ERR_GENERIC` (1, soft)
+* `OCF_ERR_ARGS` (2, hard)
+* `OCF_ERR_UNIMPLEMENTED` (3, hard)
+* `OCF_ERR_PERM` (4, hard)
+* `OCF_ERR_INSTALLED` (5, hard)
+* `OCF_ERR_CONFIGURED` (6, fatal)
+* `OCF_NOT_RUNNING` (7)
+* `OCF_RUNNING_MASTER` (8, soft)
+* `OCF_FAILED_MASTER` (9, soft)
+
+FR Chaque code retour est associé à un niveau de criticité s'il ne correspond
+FR à celui attendu par le cluster:
+FR
+FR * `soft`: le cluster tente une action corrective sur le même nœud ou déplace
+FR la ressource ailleurs
+FR * `hard`: la ressource doit être déplacée et ne pas revenir sur l'ancien nœud
+FR sans intervention humaine
+FR * `fatal`: le cluster ne peut gérer la ressource sur aucun nœud
+FR
+Each return code as a corresponding criticity, which is used when the return
+code is different from the one expected by the cluster:
+
+* `soft`: the cluster will try to make a corrective action on the same node or
+ move the resource elsewhere;
+* `hard`: the resource must be move and cannot return to the old node without
+ human intervention;
+* `fatal`: the cluster cannot manage the resource on any node.
+
+FR Voici les opérations disponibles aux agents implémentant la specification OCF:
+FR
+FR * `start`: démarre la ressource
+FR * `stop`: arrête la ressource
+FR * `monitor`: vérifie l'état de la ressource
+FR * `validate-all`: valide la configuration de la ressource
+FR * `meta-data`: présente les capacités de l'agent au cluster
+FR * `promote`: promote la ressource slave en master
+FR * `demote`: démote la ressource master en slave
+FR * `migrate_to`: actions à réaliser pour déplacer une ressource vers un autre nœud
+FR * `migrate_from`: actions à réaliser pour déplacer une ressource vers le nœud local
+FR * `notify`: action à exécuter lorsque le cluster notifie l'agent des actions
+FR le concernant au sein du cluster
+FR
+These are the available operations for the agent who implement the _OCF_
+specification:
+
+* `start`: start the resource
+* `stop`: stop resource
+* `monitor`: check the state resource
+* `validate-all`: validate the configuration of the resource
+* `meta-data`: displays the capabilities of the _RA_
+* `promote`: promote the slave resource into a master
+* `demote`: demote a master resource to a slave
+* `migrate_to`: required action in order to move the resource to another node
+* `migrate_from`: required action in order to move the resource to the local
+ node
+* `notify`: action to execute when the cluster notifies the _RA_ of the actions
+ it must execute
+
+FR L'opération `meta-data` permet à l'agent de documenter ses paramètres et
+FR d'exposer ses capacités au cluster qui adapte donc ses décisions en fonction
+FR des actions possibles. Par exemple, si les actions `migrate_*` ne sont pas
+FR disponibles, le cluster utilise les actions `stop` et `start` pour déplacer
+FR une ressource.
+FR
+The `meta-data` operation is used by the agent to document it's configuration
+and expose it's capabilities to the cluster. The cluster will then adapt it's
+decision according to the available actions. For example, if the `migrate_*`
+action are not available, the cluster will use the `stop` and `start` actions
+to move a resource.
+
+FR Les agents systemd ou sysV sont limités aux seules actions `start`, `stop`,
+FR `monitor`. Dans ces deux cas, les codes retours sont interprétés par `LRMd`
+FR comme étant ceux définis par la spécification LSB:
+FR
+FR
+The systemd and sysV agent are limited to three actions `start`, `stop` and
+`monitor`. With these agents `LRMd` interprets the return codes as described in
+the LSB specification:
+
+
+FR Un ressource peut gérer un service seul (eg. une vIP) au sein du cluster, un
+FR ensemble de service cloné (eg. Nginx) ou un ensemble de clone _multi-state_
+FR pour lesquels un statut `master` et `slave` est géré par le cluster et le _RA_.
+FR
+A resource can manage a single service (e.g. a VIP), or a group of cloned
+services (e.g. Nginx) or even a group of _multi-state_ clones where the
+`master` and `slave` state is managed by the cluster and the _RA_.
+
+FR Les _RA_ qui pilotent des ressources _multi-state_ implémentent obligatoirement
+FR les actions `promote` et `demote` : une ressource est clonée sur autant de
+FR nœuds que demandé, démarrée en tant que slave, puis le cluster promeut un ou
+FR plusieurs `master` parmi les `slave`.
+FR
+The _RA_ designed to control _multi-state_ resources must implement the
+`promote` and `demote` actions: the resource will be cloned on as many nodes as
+requested, started as a slave, then the cluster will promote one or several
+`masters` amongst the `slaves`.
+
+FR Le _resource agent_ PAF utilise intensément toutes ces actions, sauf
+FR `migrate_to` et `migrate_from` qui ne sont disponibles qu'aux _RA_ non
+FR _multi-state_ (non implémenté dans Pacemaker pour les ressources multistate).
+FR
+The _resource agent_ PAF uses all theses actions except for `migrate_to` and
+`migrate_from` which are available only for non _multi-state_ _RA_ (it's not
+implemented in Pacemaker for multi state resources).
+
+:::
+
+-----
+
+### Practical work: _Resource Agents_
+
+::: notes
+
+FR 1. installer les _resource agents_
+FR 2. lister les RA installés à l'aide de `pcs`
+FR 3. afficher les informations relatives à l'agent `dummy` à l'aide de `pcs`
+FR 4. afficher les informations relatives à l'agent `pgsql` à l'aide de `pcs`
+FR
+1. install the _resource agents_
+2. list the available _RA_ with `pcs`
+3. display the information about the `dummy` _RA_ with `pcs`
+4. display the information about the `pgsql` _RA_ with `pcs`
+
+:::
+
+-----
+
+### Correction: _Resource Agents_
+
+::: notes
+
+FR 1. installer les _resource agents_
+FR
+FR Il est normalement déjà installé comme dépendance de pacemaker.
+FR
+1. install the _resource agents_
+
+This package is usually installed as a dependency of Pacemaker.
+
+~~~
+yum install -y resource-agents
+~~~
+
+FR 2. lister les RA installés à l'aide de `pcs`
+FR
+2. list the available _RA_ with `pcs`
+
+~~~
+pcs resource agents
+~~~
+
+FR 3. afficher les informations relatives à l'agent `dummy` à l'aide de `pcs`
+FR
+FR Chaque agent embarque sa propre documentation.
+FR
+3. display the information about the `dummy` _RA_ with `pcs`
+
+Each _RA_ contains it's own documentation.
+
+~~~
+pcs resource describe dummy
+~~~
+
+FR 4. afficher les informations relatives à l'agent `pgsql` à l'aide de `pcs`
+FR
+FR Le RA `pgsql` livré avec le paquet `resource-agents` n'est **pas** celui de PAF. Vous
+FR pouvez lister l'ensemble de ses options grâce à la commande:
+FR
+
+4. display the information about the `pgsql` _RA_ with `pcs`
+
+The `pgsql` _RA_ is deployed with the `resource_agents` package is the one
+deployed with PAF.
+
+You can list all it's options with the command :
+
+~~~
+pcs resource describe pgsql
+~~~
+
+:::
+
+-----
+
+## PostgreSQL Automatic Failover (PAF)
+
+FR * _RA_ spécifique à PostgreSQL pour Pacemaker
+FR * alternative à l'agent existant
+FR * moins complexe et moins intrusif
+FR * compatible avec PostgreSQL 9.3 et supérieur
+FR * Voir:
+FR
+* _RA_ dedicated to PostgreSQL
+* an alternative to the existing one
+ - less complex and intrusive
+ - compatible with PostgreSQL 9.3 and up
+* see:
+
+::: notes
+
+FR PAF se situe entre Pacemaker et PostgreSQL. C'est un _resource agent_
+FR qui permet au cluster d'administrer pleinement une instance PostgreSQL locale.
+FR
+FR Un chapitre entier est dédié à son installation, son fonctionnement et sa
+FR configuration plus loin dans ce workshop.
+FR
+FR 
+FR
+PAF is a component placed between Pacemaker and PostgreSQL. It's a _resource
+agent_ which enables the cluster to administer a local PostgreSQL instance.
+
+A chapter dedicated to it's installation, inner working and configuration can
+be found later in this workshop.
+
+
+:::
+
+------
+
+# Cluster configuration
+
+FR Attention:
+FR
+FR * les paramètres de Pacemaker sont tous sensibles à la casse
+FR * aucune erreur n'est levée en cas de création d'un paramètre inexistant
+FR * les paramètres inconnus sont simplement ignorés par Pacemaker
+FR
+Warning:
+
+* Pacemaker's parameters are all case sensitive
+* no error is returned when a non existant parameter is created
+* unknown parameters are juste ignored by Pacemaker
+
+-----
+
+## Quorum support
+
+FR Paramètre `no-quorum-policy`
+FR
+FR * `ignore`: désactive la gestion du quorum (déconseillé !)
+FR * `stop`: (par défaut) arrête toutes les ressources
+FR * `freeze`: préserve les ressources encore disponible dans la partition
+FR * `suicide`: fencing des nœuds de la partition
+FR
+The `no-quorum-policy` parameter
+
+* `ignore`: disables quorum management (not recommanded)
+* `stop`: stop the resources (default)
+* `freeze`: keeps the resources that are still available in the partition
+* `suicide`: fence the nodes of the partition
+
+:::notes
+
+FR Il est fortement déconseillé de désactiver le quorum.
+FR
+FR La valeur par défaut est le plus souvent la plus adaptée.
+FR
+FR Le cas du `freeze` peut être utile afin de conserver les ressources actives au
+FR sein d'un cluster où il n'y a aucun risque de split brain en cas de partition
+FR réseau, eg. un serveur httpd.
+FR
+
+It's strongly advised not to disable quorum.
+
+Most of the time, the default value is the most suitable.
+
+The `freeze` value can be useful in order to keep resources active in a cluster
+where there is no risk of split brain in case of network partition (e.g. an
+httpd server).
+
+:::
+
+-----
+
+## Stonith support
+
+FR Paramètre `stonith-enabled`
+FR
+FR * `false` : désactive la gestion du fencing (déconseillé !)
+FR * activé par défaut
+FR * aucune ressource ne démarre sans présence de FA
+FR
+The `stonith-enabled` parameter
+
+* `false`: disables the fencing (not recommanded)
+* enabled by default
+ - no ressource can start without _FA_
+
+:::notes
+
+FR Ce paramètre contrôle la gestion du fencing au sein du cluster. Ce dernier
+FR est activé et il est vivement recommandé de ne pas le désactiver.
+FR
+FR Effectivement, il est possible de désactiver le fencing au cas par cas,
+FR ressource par ressource, grâce à leur méta-attribut `requires` (voir
+FR chapitre [Configuration des ressources][]), positionné par défaut à `fencing`.
+FR
+This parameter controls fencing management inside the cluster. It's enabled by
+default. It's not recommanded to disable it.
+
+If need be, it's possible to disable fencing peacemeal, one resource at a
+time with their meta attribute `requires` (see the [Resource configuration][]
+chapter). It's default value is `fencing`.
+
+FR Il est techniquement possible de désactiver le [quorum][] ou [fencing][].
+FR
+FR Comme dit précédemment c'est à proscrire hors d'un environnement de test. Sans
+FR ces fonctionnalités, le comportement du cluster est imprévisible en cas de
+FR panne et sa cohérence en péril.
+FR
+FR Dans le cas d'un cluster qui gère une base de donnée cela signifie que l'on encourt le
+FR risque d'avoir plusieurs ressources PostgreSQL disponibles en écriture sur plusieurs
+FR nœuds (conséquence d'un `split brain`).
+FR
+It's possible to disable [quorum][] or [fencing][].
+
+As explained before, this is not recommanded outside of a test environement.
+Without these mechanisms, the cluster behavior is unpredictable in case of
+outage and it's consistency is at risk.
+
+In case of clusters that manage databases, this means we risk a `split brain`
+situation in case of network partition. Which will result in the same database
+being opened in read/write mode on different nodes.
+
+:::
+
+-----
+
+## Symetric and asymetric clusters
+
+FR Paramètre `symmetric-cluster`:
+FR
+FR * change l'effet des scores de préférence des ressources
+FR * `true`: (par défaut) cluster symétrique ou _Opt-Out_. Les ressources
+FR peuvent démarrer sur tous les nœuds à moins d'y avoir un score déclaré
+FR inférieur à `0`
+FR * `false`: cluster asymétrique ou _Opt-In_. Les ressources ne peuvent
+FR démarrer sur un nœud à moins d'y avoir un score déclaré supérieur ou
+FR égal à `0`
+FR
+The `symetric-cluster` parameter
+
+* changes the effect of preference scores on resources
+* `true`: the cluster is symetric or _Opt-Out_, this is the default. The
+ resources can start on all nodes except if there is a negative score placed
+ on the node.
+* `false`: the cluster is asymetric or _Opt-In_. The resources cannot start on
+ a node unless a positive score as been placed on the node.
+
+::: notes
+
+FR Le paramètre `symetric-cluster` permet de changer la façon dont pacemaker choisit
+FR où démarrer les ressources.
+FR
+FR Configuré à `true` (defaut), le cluster est dit symétrique. Les ressources
+FR peuvent être démarrées sur n'importe quel nœud. Le choix se fait par ordre
+FR décroissant des valeurs des [contraintes de localisation][Scores etlocalisation].
+FR Une contrainte de localisation négative empêchera la ressource de démarrer
+FR sur un nœud.
+FR
+FR Configuré à `false`, le cluster est dit asymétrique. Les ressources ne peuvent
+FR démarrer nulle part. La définition des contraintes de localisation doit définir
+FR sur quels nœuds les ressources peuvent être démarrées.
+FR
+FR La notion de contraintes de localisation est définie dans le chapitre
+FR [Contraintes de localisation][]
+FR
+The `symetric-cluster` parameter changes the way pacemaker choses where to
+start resources.
+
+The default value is `true`, in this case the cluster is called symetric. The
+resources can start on any node. The choice of the node is made in decreasing
+order of the [location constraints][Scores and location constraints]. A negative location
+constraint prevents a resource to start on the node.
+
+When it is set to `false`, the cluster is said to be `asymetric`. The resource
+cannot start anywhere. Location constraints must be set to define where the
+resource can start.
+
+The notion of [location constraints][] is defined in it's own chapter.
+
+:::
+
+-----
+
+## Maintenance mode
+
+FR Paramètre `maintenance-mode`:
+FR
+FR * désactive tout contrôle du cluster
+FR * plus aucun opération n'est exécutée
+FR * plus de monitoring des ressources
+FR * les ressources démarrée sont laissée dans leur état courant (elles ne
+FR sont pas arrêtées)
+FR * toujours tester les transitions avec `crm_simulate` avant de sortir de la
+FR maintenance
+FR
+The `maintenace-mode` parameter
+
+* disables all control on the cluster
+* no more action will be executed
+ - no monitoring will be done on resources
+* the started resources will be left in their current state
+* always test the transition with `crm_simulate` when leaving maintenance mode
+
+::: notes
+
+FR Le paramètre `maintenance_mode` est utile pour réaliser des opérations de
+FR maintenance globales à tous les nœuds du cluster. Toutes les opérations
+FR `monitor` sont désactivées et le cluster ne réagit plus aucun événements.
+FR
+FR Ce paramètre, comme tous les autres, est préservé lors du redémarrage de
+FR Pacemaker, sur un ou tous les nœuds. Il est donc possible de redémarrer tout
+FR le cluster tout en conservant le mode maintenance actif.
+FR
+The `maintenance mode` parameter is useful to conduct maintenace operations
+that impact all the nodes of the cluster. All the `monitor` action are disables
+and the cluster doesn't react to any event.
+
+This parameter, like all others, is kept during Pacemaker restarts. It's
+therefore possible to restart all the cluster while keeping the maintenance
+mode active.
+
+FR Attention toutefois aux scores de localisation. D'autant plus que ceux-ci
+FR peuvent être mis à jour lors du démarrage du cluster sur un nœud par exemple.
+FR Vérifiez toujours que les ressources sont bien dans l'état attendu sur chaque
+FR nœud avant de sortir du mode de maintenance afin d'éviter une intervention du
+FR cluster. Lorsque ce dernier reprend la main, il lance l'action `probe` sur
+FR toutes les ressources sur tous les nœuds pour détecter leur présence et
+FR comparer la réalité avec l'état de sa CIB.
+FR
+Be careful to the location scores, they can be updated during cluster restart.
+It's important to verify that all resources are in the correct state on all
+nodes before leaving maintenance mode in order to avoid changes in the cluster
+state. When the cluster is back in control, it starts a `probe` action on all
+resources of all nodes in order to detect their presence and compare reality
+with the state recorded in the CIB.
+
+:::
+
+-----
+
+## Other usefull parameters
+
+FR * `stop-all-resources=false`: toutes les ressources sont arrêtées si
+FR positionné à `true`
+FR * `stonith-watchdog-timeout`: temps d'attente avant qu'un nœud disparu est
+FR considéré comme "auto-fencé" par son watchdog si le cluster est configuré
+FR avec
+FR * `cluster-recheck-interval=15min`: intervalle entre deux réveils forcé du
+FR `PEngine` pour vérifier l
+FR 'état du cluster
+FR
+* `stop-all-resources=false`: all resources are stopped if this parameter is
+ set to `true`
+* `stonith-watchdog-timeout`: elapsed time before a failed node is considered
+ "self fenced" by it's watchdog if the cluster has one.
+* `cluster-recheck-interval=15min`: interval between two forced awakening of
+ the `PEngine` in order to check the cluster state
+
+::: notes
+
+FR Pour la liste complète des paramètres globaux du cluster, voir:
+FR
+A compehensive list of cluster global parameters is available here:
+
+
+
+:::
+
+-----
+
+## Practical work: Cluster parameters
+
+::: notes
+
+FR 1. afficher les valeurs par défaut des paramètres suivants à l'aide de `pcs property`:
+FR
+1. display the default values of the following parameters with `pcs property`:
+
+ * `no-quorum-policy`
+ * `stonith-enabled`
+ * `symmetric-cluster`
+ * `maintenance-mode`
+
+:::
+
+-----
+
+## Correction: Cluster parameters
+
+::: notes
+
+FR 1. afficher les valeurs par défaut des paramètres suivants à l'aide de `pcs property`:
+FR
+1. display the default values of the following parameters with `pcs property`:
+
+ * `no-quorum-policy`
+ * `stonith-enabled`
+ * `symmetric-cluster`
+ * `maintenance-mode`
+
+
+~~~console
+# pcs property list --defaults|grep -E "(no-quorum-policy|stonith-enabled|symmetric-cluster|maintenance-mode)"
+ maintenance-mode: false
+ no-quorum-policy: stop
+ stonith-enabled: true
+ symmetric-cluster: true
+~~~
+
+:::
+
+-----
+
+# Node attributes
+
+## General information about node attributes
+
+FR * attributs propres à chaque nœud
+FR * peut être persistant après reboot ou non
+FR * peut stocker n'importe quelle valeur sous n'importe quel nom
+FR * eg. `kernel=4.19.0-8-amd64`
+FR
+* node specific attributes
+* can be persistent (survive a reboot or not)
+* can store any value under any name
+ - eg. `kernel=4.19.0-8-amd64`
+
+::: notes
+
+FR Il est possible de créer vos propres attributs avec l'outil `crm_attribute`.
+FR
+FR La persistance de vos attributs se contrôle avec l'argument `--lifetime`:
+FR
+FR * valeur réinitialisée au redémarrage (non persistant) : `--lifetime reboot`
+FR * note : `--type status` est également accepté. Mentionné dans la
+FR documentation mais pas dans le manuel de la commande
+FR * valeur conservée au redémarrage (persistant) : `--lifetime forever`
+FR * note : `--type nodes` est également accepté. Mentionnée dans la
+FR documentation mais pas dans le manuel de la commande
+FR
+
+It's possible to create your own attributes with the tool `crm_attribute`.
+
+The lifetime of you attribute is control with the `--lifetime` argument of the
+command:
+
+* `--lifetime reboot`: the value is reset during a restart of the cluster (it's
+ not pesistent)
+ - note: `--type status` is also accepted. It's mentionned in the
+ documentation but not in the command's manual.
+* `--lifetime forever`: the value is persistant across cluster restarts
+ - note: `--type nodes` is also accepted. It's mentionned in the documentation
+ but not in the command's manual.
+
+FR Exemple pour stocker dans un attribut du nœud nommé `kernel` la version du
+FR noyau système :
+FR
+This example shows how to create a `kernel` attribute with the kernel version
+as a value:
+
+~~~
+crm_attribute -l forever --node hanode1 --name kernel --update $(uname -r)
+~~~
+
+FR Exemple de l'utilisation d'une rule basée sur un attribut de ce type:
+The following link shows an example of how to setup rules based on attributes:
+
+
+FR Le _RA_ PAF utilise également les attributs non persistants et très
+FR transitoires. À l'annonce d'une promotion, chaque esclave renseigne son LSN
+FR dans un attribut transient. Lors de la promotion, le nœud "élu" compare son LSN
+FR avec celui des autres nœuds en consultant leur attribut `lsn_location` pour
+FR s'assurer qu'il est bien le plus avancé. Ces attributs sont détruits une fois
+FR l'élection terminée.
+FR
+The PAF _RA_ also uses non persistant attributes. During a promotion, each
+slave announces it's LSN using a transient attribute. During the promotion, the
+elected node compares it's LSN with the `lsn_location` attribute of the
+resource on each node in order to verify that it's the most up to date. These
+attributes are destroyed once the election is finished.
+
+:::
+
+-----
+
+## Spetial node attributes
+
+FR * plusieurs attributs font office de paramètres de configuration
+FR * `maintenance`: mode maintenance au niveau du nœud
+FR * `standby`: migrer toutes les ressources hors du nœud
+FR
+* several attributes are used as configuration parameters
+* `maintenance`: is the node in maintenance mode
+* `standby`: migrate resource outside of the node
+
+::: notes
+
+FR Il existe plusieurs attributs de nœuds spéciaux qui font offices de
+FR paramétrage. Les deux plus utiles sont `maintenance` et `standby`.
+FR
+FR L'attribut `maintenance` a le même effet que le `maintenance_mode` au niveau
+FR du cluster, mais localisé au seul nœud sur lequel il est activé.
+FR
+FR Lorsque l'attribut `standby` est activé, il indique que le nœud ne doit plus
+FR héberger aucune ressource. Elle sont alors migré vers d'autres nœuds ou
+FR arrêté le cas échéant.
+FR
+FR Vous trouverez la liste complète de ces attributs de nœud spéciaux à
+FR l'adresse suivante:
+FR
+Several special node attributes are used as configuration parameters. The two
+most useful are `maintenance` and `standby`.
+
+The `maintenance` attribute as the same effect as the `maintenance_mode` cluster
+wide parameter, except that it's limited only to the node it's placed on.
+
+When the `standby` attribute is activated, it indicates that the node cannot
+host resource anymore. They will be migrated to other nodes ou stopped.
+
+A more compehensive list of special node attribute is available a the folling
+address:
+
+
+:::
+
+-----
+
+## Other node attribute of interest
+
+FR Quelques autres attributs particuliers:
+FR
+FR * `fail-count-*`: nombre d'incident par ressource sur le nœud
+FR * `master-*`: _master score_ de la ressource sur le nœud
+FR
+Some other node attributes of interest
+
+* `fail-count-*`: number of incident for a resource on a node
+* `master-*`: the _master score_ of a resouce on a node
+
+::: notes
+
+FR Un attribut `fail-count-*` de type non persistant est utilisés pour
+FR mémoriser le nombre d'erreur de chaque ressources sur chaque nœud. Préférez
+FR utiliser `crm_failcount` ou `pcs resource failcount` pour accéder à ces
+FR informations.
+FR
+Non persistent `fail-count-*` attributes are used to memorize the amount of
+errors for each resource on a node. It's a good practice to use `crm_failcount`
+or `pcs resource failcount` to access this information instead of accessible
+the attributes directly.
+
+FR Enfin, il existe des _master score_ pour les ressources de type _multi-state_
+FR (primaire/secondaire), permettant d'indiquer où l'instance primaire peut ou
+FR doit se trouver dans le cluster. Il sont préfixé par `master-*`. PAF positionne
+FR ces scores comme attributs persistants des nœuds. La position de l'instance
+FR primaire est ainsi préservée lors du redémarrage du cluster.
+FR
+FR Vous pouvez consulter ou modifier les _master score_ à l'aide de l'outil
+FR `crm_master`. Attention toutefois, ces scores sont positionnés habituellement
+FR par le _RA_ lui même. À moins de vous trouver dans une situation où le
+FR cluster ne nomme aucune ressource primaire, vous ne devriez pas vous même
+FR positionner un _maser score_.
+FR
+
+Finally, a _master score_ attribute exists for _multi-state_ resources
+(primary/secondary), it's used to specify where the primary instance can/must
+be placed in the cluster. They are prefixed with `master-*`. PAF uses theses
+scores as persistent attributes on each node. Unless you want the cluster to be
+unable to chose a primary resource, you shouldn't specify a _maaster score_
+yourself.
+
+:::
+
+-----
+
+# Resource configuration
+
+FR * mécanique interne
+FR * __tout__ dépend des scores !
+FR * chapitre organisé dans l'ordre des besoins de configuration
+FR
+* internal mechanics
+* __everything__ depends on scores !
+* this chapter's organization is based on the order of configuration needs
+
+-----
+
+## Resource meta-attributes
+
+FR * un ensemble de _meta-attributes_ s'appliquent à n'importe quelle ressource:
+FR * il est possible de leur positionner une valeur par défaut qui s'applique
+FR à toutes les ressources
+FR * il est possible de surcharger les valeurs par défaut pour chaque ressource
+FR * quelques exemple de méta-attributs:
+FR * `target-role`: rôle attendu: `Started`, `Stopped`, `Slave`, ou `Master`
+FR * `migration-threshold` : combien d'erreurs "soft" avant de déclencher un failover
+FR * `failure-timeout` : durée à partir de laquelle les erreurs "soft" sont réinitialisées
+FR * `resource-stickiness` : score de maintien d'une ressource sur le nœud courant
+FR * `is-managed`: le cluster doit-il agir en cas d'événement ?
+FR
+* a set of _meta-attributes_ can be applied to any resource:
+ - it's possible to set a default value which will be applied to all resources
+ - it's possible to overload all the default values
+* some example of meta attributes:
+ - `target-role`: expected role among: `Started`, `Stopped`, `Slave or
+ `Master`
+ - `migration-threshold`: how many "soft" errors before we start a failover
+ - `failure-timeout`: amount of time elapsed before the "soft" errors are
+ reset
+ - `resource-stickiness`: controls how much a service prefers to stay running
+ where it is
+ - `is-managed`: does the cluster react in case of event ?
+
+::: notes
+
+FR Les _meta-attributes_ est un ensemble d'attributs commun à n'importe quelle
+FR type de ressource. Ils se positionnent ressource par ressource. Il est possible
+FR de leur créer une valeur par défaut qui sera appliquée automatiquement à toute
+FR ressource présente dans le cluster.
+FR
+FR Par exemple avec `pcs`:
+FR
+_Meta-attributes_ are a set of attributes shared by all types of resources.
+They can be set on a resource per resource basis. It's possible to change their
+default value so that it's applied to all the resources in the cluster.
+
+Exemple using `pcs`:
+
+~~~
+pcs resource defaults =valeur
+~~~
+
+FR Le même exemple avec l'outil standard `crm_attribute`:
+FR
+
+The same example using `crm_attribute`:
+
+~~~
+crm_attribute --type rsc_defaults --name --update valeur
+~~~
+
+FR La valeur d'un méta attribut positionné au niveau de la ressource elle même
+FR surcharge la valeur par défaut positionné précédemment.
+FR
+FR La liste complète des méta-attributs et leur valeur par défaut est disponible à
+FR cette adresse:
+FR
+The value of a meta attribute positionned at the resource level takes priority
+over default values configures at a higher level.
+
+A comprehensive list of meta-attributes and their default value is available
+here:
+
+
+:::
+
+-----
+
+### Practical work: resource default parameters
+
+::: notes
+
+FR 1. trouver la valeur par défaut du paramètre `migration-threshold`
+FR 2. positionner sa valeur à dix
+FR 3. supprimer la valeur par défaut du paramètre `is-managed`
+FR 4. contrôler que les modifications sont prise en compte avec `pcs config show`
+FR 5. observer les modifications de la CIB dans les logs
+FR
+FR Remarque: il existe une propriété du cluster `default-resource-stickiness`.
+FR Cette propriété est dépréciée, il faut utiliser les valeurs par defaut des
+FR ressources à la place.
+FR
+1. find the default value of the parameter `migration-threshold`
+2. set it to a value of 10
+3. remove the default value for the parameter `is-managed`
+4. check that the modification where taken into account with `pcs config show`
+5. look for the CIB modification in the logs
+
+Note: the property `default-resource-stickiness` is deprecated. The per
+resource default value should be used instead.
+
+~~~
+pcs property list --defaults |grep -E "resource-stickiness"
+ default-resource-stickiness: 0
+~~~
+
+:::
+
+-----
+
+### Correction: resource default parameters
+
+::: notes
+
+FR 1. trouver la valeur par défaut du paramètre `migration-threshold`
+FR
+FR La valeur par défaut est `INFINITY`. Voir:
+FR
+1. find the default value of the parameter `migration-threshold`
+
+The default value is set to `INFINITY`. See:
+
+
+
+2. positionner sa valeur à dix
+
+FR 2. set it to a value of 10
+FR
+~~~console
+# pcs resource defaults migration-threshold=10
+Warning: Defaults do not apply to resources which override them with their own defined values
+# pcs resource defaults
+migration-threshold: 10
+~~~
+
+3. supprimer la valeur par défaut du paramètre `is-managed`
+
+FR 3. remove the default value for the parameter `is-managed`
+FR
+~~~console
+# pcs resource defaults is-managed=
+Warning: Defaults do not apply to resources which override them with their own defined values
+~~~
+
+FR 4. contrôler que les modifications sont prise en compte avec `pcs config show`
+FR
+4. check that the modification where taken into account with `pcs config show`
+
+~~~
+# pcs config show
+[...]
+Resources Defaults:
+ migration-threshold=10
+[...]
+~~~
+
+FR 5. observer les modifications de la CIB dans les logs
+FR
+FR NB: les log ont ici été remis en forme.
+FR
+5. look for the CIB modification in the logs
+
+Note: the logs where reformatted to fit the workshop.
+
+~~~
+cib: info: Forwarding cib_apply_diff operation for section 'all' to all
+cib: info: Diff: --- 0.5.5 2
+cib: info: Diff: +++ 0.6.0 2edcd42b63c34c8c39f2ab281d0c09b8
+cib: info: + /cib: @epoch=6, @num_updates=0
+cib: info: ++ /cib/configuration:
+cib: info: ++
+cib: info: ++
+cib: info: ++
+cib: info: ++
+cib: info: ++
+cib: info: Completed cib_apply_diff operation for section 'all': OK
+~~~
+
+:::
+
+-----
+
+## Fencing configuration
+
+FR * les _FA_ sont gérés comme des ressources classiques
+FR * les _FA_ ont un certain nombre de paramètres en commun: `pcmk_*`
+FR * les autres paramètres sont propres à chaque _FA_, eg. `port`, `identity_file`, `username`, ...
+FR * chaque _FA_ configuré peut être appelé de n'importe quel nœud
+FR
+* _FA_ are handled like regular resources
+* _FA_ have a bunch of: `pcmk_*` parameters
+* other parameters exist and are _FA_ specific, eg. `port`, `identity_file`,
+ `username`, ...
+* each configured _FA_ can be called from any node
+
+::: notes
+
+FR Pour chaque agent de fencing configuré, un certain nombre de méta attributs
+FR définissent les capacités de l'agent auprès du cluster. Quelque exemples
+FR notables:
+FR
+FR * `pcmk_reboot_action`: détermine quelle action exécuter pour isoler un nœud.
+FR Par exemple `reboot` ou `off`. L'action indiquée dépend de ce que supporte
+FR l'agent
+FR * `pcmk_host_check`: détermine si l'agent doit interroger l'équipement pour
+FR établir la liste des nœuds qu'il peut isoler, ou s'il doit se reposer sur
+FR le paramètre `pcmk_host_list`
+FR * `pcmk_host_list`: liste des nœuds que peut isoler l'agent de fencing
+FR * `pcmk_delay_base`: temps d'attente minimum avant de lancer l'action de
+FR fencing. Pratique dans les cluster à deux nœuds pour privilégier un des
+FR nœuds
+FR
+FR Vous trouverez la liste complète à l'adresse suivante:
+
+For each configured fencing agent, a few meta attributes define the
+capabilities of the agent to the cluster. Some notable examples:
+
+* `pcmk_reboot_action`: determines which action to execute in order to isolate
+ a node. For example `reboot` or `off`. the action provided depends upon what
+ the agent supports.
+* `pcmk_host_check`: determines if the agent must ask the equipment for a list
+ of nodes it can isolate, or if it must rely on the `pcmk_host_list`
+ parameter.
+* `pcmk_host_list`: list the nodes that the _FA_ can isolate
+* `pcmk_delay_base`: minimum elapsed time before starting the fencing action.
+ It's useful in two node cluster to favor one node over the other.
+
+The full list can be found here:
+
+
+FR Tous les paramètres ne débutants pas par `pcmk_*` sont propres à chaque
+FR _fencing agent_. Dans le cadre de notre workshop, nous utiliserons l'agent
+FR `fence_virsh` qui nécessite des paramètres de connexion SSH ainsi que le nom
+FR de la machine virtuelle à interrompre.
+FR
+All the parameters who dont start with `pcmk_*` are specific to each _fencing
+agent_. In this workshop, we will use the fencing agent `fence_virsh`. It
+requires several specific parameters for the SSH connexion like the name of the
+virtual machine to stop.
+
+FR Une fois paramétrés, Pacemaker s'assure que les _FA_ restent disponibles en
+FR exécutant à intervalle régulier l'action `monitor`, positionnée par défaut
+FR à une minute. À cause de cette action récurrente, les _FA_ apparaissent au
+FR sein du cluster au même titre que les autres ressources. Mais notez qu'une
+FR ressource de fencing ne démarre pas sur les nœud du cluster, ces équipement
+FR sont actifs _ailleurs_ dans votre architecture.
+FR
+Once configured, Pacemaker will make sure the _FA_ are available at all times
+with the execution of a regular `monitor` action. The default interval is set
+to a minute. Because of the recuring actions, the _FA_ appear in the cluster
+the same way as other resources do. Please note that the fencing resource is
+not started on the cluster nodes, it's equipments are active somewhere else in
+the architecture.
+
+FR Lorsqu'une action de fencing commandée par Pacemaker, celle-ci sera déclenchée
+FR en priorité depuis le nœud d'où la ressource est supervisée. Si le nœud ou
+FR la ressource de fencing sont devenus indisponibles depuis la dernière action de
+FR monitor, n'importe quel autre nœud du cluster peut être utilisé pour
+FR exécuter la commande.
+FR
+When a fencing action is requested by Pacemaker, it will be executed in
+priority on the node where the resource is supervised. If the node or the
+fencing resource are unavailable since the last monitor, any other node of the
+cluster can be used to execute the command.
+
+:::
+
+-----
+
+### Practical work: Fencing Agent
+
+::: notes
+
+FR Rappel: par défaut le cluster refuse de prendre en charge des ressources en HA sans
+FR fencing configuré.
+FR
+Reminder: the default behavior for the cluster is to refuse to start any
+resource if there is no fencing configured.
+
+~~~console
+# crm_verify --verbose --live-check
+~~~
+
+FR 1. afficher la description de l'agent de fencing `fence_virsh`
+FR
+FR Nous allons utiliser les paramètres suivants:
+FR
+FR * `ipaddr`: adresse de l'hyperviseur sur lequel se connecter en SSH
+FR * `login`: utilisateur SSH pour se connecter à l'hyperviseur
+FR * `identity_file`: chemin vers la clé privée SSH à utiliser pour l'authentification
+FR * `login_timeout`: timeout du login SSH
+FR * `port`: nom de la VM à isoler dans libvirtd
+FR
+FR Les autres paramètres sont décrits dans le slide précédent.
+FR
+FR Bien s'assurer que chaque nœud peut se connecter en SSH sans mot de passe à
+FR l'hyperviseur.
+FR
+1. display the desciption of the _FA_ `fence_virsh`
+
+We will use the following parameters:
+
+* `ipaddr`: address of the hypervisor on which we will connect with SSH
+* `login`: user for the SSH connection to the hypervisor
+* `identity_file`: path to the SSH private key used for authentication
+* `login_timeout`: timeout for the SSH login
+* `port`: name of the VM to isolate in libvirtd
+
+The other parameters are described in the previous slides.
+
+It's important to check that passwordless authentication is configured between
+the nodes and the hypervisor.
+
+FR 2. créer une ressource de fencing pour chaque nœud du cluster
+FR
+FR Les agents de fencing sont des ressources en HA prises en charge par le
+FR cluster. Dans le cadre de ce TP, nous créons une ressource par nœud,
+FR chacune responsable d'isoler un nœud.
+FR
+2. create a fencing resource for each node in the cluster
+
+The fencing agents are HA resources managed by the cluster. In this exercise,
+we will create one resource per node each one will be responsible for fencing a
+node.
+
+FR 3. vérifier que le cluster ne présente plus d'erreur
+FR 4. vérifier que ces ressources ont bien été créées et démarrées
+FR 5. afficher la configuration des agents de fencing
+FR 6. vérifier dans les log que ces ressources sont bien surveillée par `LRMd`
+FR
+3. verify that the cluster doesn't have any error
+4. verify that the resources have been created and started
+5. display the configuration of the fencing agents
+6. verify that the resources are supervized by `LRMd` in the logs
+
+:::
+
+-----
+
+### Correction: Fencing Agent
+
+::: notes
+
+FR Rappel: par défaut le cluster refuse de prendre en charge des ressources en HA sans
+FR fencing configuré.
+FR
+Reminder: the default behavior for the cluster is to refuse to start any
+resource if there is no fencing configured.
+
+~~~console
+# crm_verify --verbose --live-check
+ error: unpack_resources: Resource start-up disabled since no STONITH resources have been defined
+ error: unpack_resources: Either configure some or disable STONITH with the stonith-enabled option
+ error: unpack_resources: NOTE: Clusters with shared data need STONITH to ensure data integrity
+Errors found during check: config not valid
+~~~
+
+FR 1. afficher la description de l'agent de fencing `fence_virsh`
+FR
+1. display the desciption of the _FA_ `fence_virsh`
+
+~~~
+# pcs resource describe stonith:fence_virsh
+~~~
+
+FR 2. créer une ressource de fencing pour chaque nœud du cluster
+FR
+FRAdapter `pcmk_host_list`, `ipaddr`, `login` et `port` à votre environnement.
+FR
+2. create a fencing resource for each node in the cluster
+
+Adapt `pcmk_host_list`, `ipaddr`, `login` and `port` to your environnment.
+
+~~~console
+# pcs stonith create fence_vm_hanode1 fence_virsh pcmk_host_check="static-list" \
+pcmk_host_list="hanode1" ipaddr="10.20.30.1" login="user" \
+port="centos7_hanode1" pcmk_reboot_action="reboot" \
+identity_file="/root/.ssh/id_rsa" login_timeout=15
+
+# pcs stonith create fence_vm_hanode2 fence_virsh pcmk_host_check="static-list" \
+pcmk_host_list="hanode2" ipaddr="10.20.30.1" login="user" \
+port="centos7_hanode2" pcmk_reboot_action="reboot" \
+identity_file="/root/.ssh/id_rsa" login_timeout=15
+
+# pcs stonith create fence_vm_hanode3 fence_virsh pcmk_host_check="static-list" \
+pcmk_host_list="hanode3" ipaddr="10.20.30.1" login="user" \
+port="centos7_hanode3" pcmk_reboot_action="reboot" \
+identity_file="/root/.ssh/id_rsa" login_timeout=15
+~~~
+
+FR 3. vérifier que le cluster ne présente plus d'erreur
+FR
+3. verify that the cluster doesn't have any error
+
+~~~console
+# crm_verify -VL
+# echo $?
+0
+~~~
+
+FR 4. vérifier que ces ressources ont bien été créées et démarrées
+FR
+4. verify that the resources have been created and started
+
+~~~console
+# pcs status
+[...]
+3 nodes configured
+3 resources configured
+
+Online: [ hanode1 hanode2 hanode3 ]
+
+Full list of resources:
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode3
+[...]
+~~~
+
+FR 5. afficher la configuration des agents de fencing
+FR
+5. display the configuration of the fencing agents
+
+~~~
+# pcs stonith show --full
+ Resource: fence_vm_hanode1 (class=stonith type=fence_virsh)
+ Attributes: identity_file=/root/.ssh/id_rsa ipaddr=10.20.30.1 login=ioguix login_timeout=15 pcmk_host_check=static-list pcmk_host_list=hanode1 pcmk_reboot_action=reboot port=paf_3n-vip_hanode1
+ Operations: monitor interval=60s (fence_vm_hanode1-monitor-interval-60s)
+ Resource: fence_vm_hanode2 (class=stonith type=fence_virsh)
+ Attributes: identity_file=/root/.ssh/id_rsa ipaddr=10.20.30.1 login=ioguix login_timeout=15 pcmk_host_check=static-list pcmk_host_list=hanode2 pcmk_reboot_action=reboot port=paf_3n-vip_hanode2
+ Operations: monitor interval=60s (fence_vm_hanode2-monitor-interval-60s)
+ Resource: fence_vm_hanode3 (class=stonith type=fence_virsh)
+ Attributes: identity_file=/root/.ssh/id_rsa ipaddr=10.20.30.1 login=ioguix login_timeout=15 pcmk_host_check=static-list pcmk_host_list=hanode3 pcmk_reboot_action=reboot port=paf_3n-vip_hanode3
+ Operations: monitor interval=60s (fence_vm_hanode3-monitor-interval-60s)
+~~~
+
+FR 6. vérifier dans les log que ces ressources sont bien surveillée par `LRMd`
+FR
+FR Les log ont été remis en forme.
+FR
+6. verify that the resources are supervized by `LRMd` in the logs
+
+Note: These logs have been reformatted.
+
+~~~
+lrmd: debug: executing - rsc:fence_vm_hanode1 action:monitor call_id:7
+lrmd: debug: finished - rsc:fence_vm_hanode1 action:monitor call_id:7 exit-code:0
+crmd: info: Result of monitor operation for fence_vm_hanode1 on hanode1: 0 (ok)
+~~~
+
+:::
+
+-----
+
+## Scores and location constraints
+
+FR * pondération interne d'une ressource sur un nœud
+FR * peut définir une exclusion si le score est négatif
+FR * `stickiness` : score de maintien en place d'une ressource sur son nœud
+FR actuel
+FR * éviter d'exclure un agent de fencing de son propre nœud définitivement
+FR * scores accessibles grâce à `crm_simulate`
+FR
+* internal weighting of a resource on a node
+* can be used to define an exclusion if the score is negative
+* `stickiness`: controls how much a service prefers to stay running
+ where it is
+* avoid the definitive exclusion of a fencing agent from it's own node
+* scores are accessible via `crm_simulate`
+
+::: notes
+
+FR Pacemaker se base sur la configuration et les scores des ressources pour
+FR calculer l'état idéal du cluster. Le cluster choisi le nœud où une ressource à
+FR le score le plus haut pour l'y placer.
+FR
+Pacemaker uses the configuration and the scores of the resources to infer the
+ideal state of the cluster. The cluster choses the node where the resource has
+the hightest score to host it.
+
+FR Les scores peuvent être positionnés comme:
+FR
+FR * contraintes de localisation ;
+FR * [contraintes de colocation][Contraintes de colocation] ;
+FR * attributs:
+FR * [`resource-stickiness`][Méta-attributs des ressources] du cluster ou des
+FR ressources ;
+FR * [`symetric-cluster`][Cluster symétrique et asymétrique] du cluster ;
+FR
+The score can be positionned as:
+
+* location constraints;
+* [colocation constraints][Colocation constraints];
+* attributes:
+ - ['resource-stickiness`][Resource meta-attributes] of the cluster or
+ resources;
+ - [`symetric-clustre`][Symetric and asymetric clusters] of the cluster.
+
+FR Ils sont aussi être manipulés tout au long de la vie du cluster. Eg.:
+FR
+FR * [bascule][Détail d'un switchover] effectuée par l'administrateur :
+FR * ban : place un score de localisation de `-INFINITY` sur le nœud courant ;
+FR * move : place un score de localisation de `+INFINITY` sur le nœud cible ;
+FR * les ressources agents pour désigner l'instance primaire grâce à un score de
+FR localisation du rôle `master`.
+FR
+They are also changed during the cluster normal operation:
+
+* [switchover][Details of a switchover]:
+ - `ban`: places a `-INFINITY` location score on the current node;
+ - `move`: places a `+INFINITY` location score on the target node;
+* multi-state resource agent chose the primary instance thanks to a location
+ score for the `master` role.
+
+FR Si pacemaker n'a pas d'instruction ou si les contraintes de localisation ont le
+FR même score alors pacemaker tente de répartir équitablement les ressources parmi
+FR les nœuds candidats. Ce comportement peut placer vos ressource de façon plus ou
+FR moins aléatoire. Un score négatif empêche le placement d'une ressource sur un nœud.
+FR
+If pacemaker as no instruction or if the location constraints have the same
+score then Pacemaker tries to allocate the resource equally between the
+candidate nodes. A negative score prevents the placement of a resource on a
+node.
+
+FR Les scores `+INFINITY` et `-INFINITY` permettent de forcer une ressource à
+FR rejoindre ou quitter un nœud de manière inconditionnelle. Voici l'arithmétique
+FR utilisée avec `INFINITY`:
+FR
+The `+INFINITY` and `-INFINITY` scores are used to force a resource to join or
+quit a node unconditionnally. The arithmetic rules for score involving
+`INFINITY` are:
+
+~~~
+INFINITY =< 1000000
+Any value + INFINITY = INFINITY
+Any value - INFINITY = -INFINITY
+INFINITY - INFINITY = -INFINITY
+~~~
+
+FR Si un nœud est sorti momentanément du cluster, par défaut ses ressources sont
+FR déplacées vers d'autres nœuds. Lors de sa réintroduction, les contraintes de
+FR localisation définies peuvent provoquer une nouvelle bascule des ressources si
+FR les scores y sont supérieurs ou égaux à ceux présents sur les autres nœuds. La
+FR plus part du temps, il est préférable d'éviter de déplacer des ressources qui
+FR fonctionnent correctement. C'est particulièrement vrai pour les base de données
+FR dont le temps de bascule peut prendre plusieurs secondes.
+FR
+If a node is momentarily excluded from a cluster, by default it's resource are
+moved to nother node. During it's reintroduction, the location contraints of
+the node can provoque another switchover of the resources if they are higher or
+equal to those present on the other nodes. Most of the time, it's preferable to
+avoid moving resources who are in are working properly. It's especially true
+for databases where the switchover can last for several seconds.
+
+FR Le paramètre `stickiness` permet d'indiquer à pacemaker à quel point une
+FR ressource en bonne santé préfère rester où elle se trouve. Pour cela la valeur
+FR du paramètre `stickiness` est additionnée au score de localisation de la
+FR ressource sur le nœud courant et comparé aux scores sur les autres nœuds pour
+FR déterminer le nœud "idéal". Ce paramètre peut être défini globalement ou par
+FR ressource.
+FR
+The `stickiness` parameter is designed to tell Pacemaker how much a resource in
+good health prefers to stay where she is running. To archive this effect, the
+valeur of the `stickiness` parameter is added to the location score of the
+resource on the current node and compared to the scores og the other nodes to
+infer the ideal node. This parameter can be set cluster wide or for a per
+resource
+
+FR Les scores de localisation sont aussi utilisés pour positionner les ressources
+FR de fencing. Vous pouvez les empêcher d'être exécutées depuis un nœud en
+FR utilisant un score d'exclusion de `-INFINITY`. Cette ressource ne sera alors ni
+FR supervisée, ni exécutée depuis ce nœud. Une telle configuration est souvent
+FR utilisée pour empêcher une ressource de fencing d'être priorisée ou déclenchée
+FR depuis le nœud qu'elle doit isoler. Néanmoins, il n'est pas recommandé
+FR d'empêcher ce comporter à tout prix. Un score négatif reste une bonne
+FR pratique, mais il est préférable d'autoriser le fencing d'un nœud depuis lui
+FR même, en dernier recours.
+FR
+FR Enfin, les scores sont consultables grâce à l'outil `crm_simulate`.
+FR
+
+The location constraints are also used to position the fencing resources. It's
+possible to forbid them from being executed from a node with an exclusion score
+of `-INFINITY`. In that case the resource will no be supervised or executed on
+the node. Such a configuration is often used to prevent a fencing resource
+from being chosen or used from the node it's supposed to isolate. Nevertheless,
+it's not recommended to forbid this behavior at all cost. A negative score is
+still an accepted practice, event if it's advise to let a fencing agent run on
+the node it's tasked to fence.
+
+Finally, these scores are visible thanks to the `crm_simulate` tool.
+
+:::
+
+-----
+
+### Practical work: Location constraint creation
+
+::: notes
+
+FR 1. afficher les scores au sein du cluster
+FR
+FR Noter quel nœud est responsable de chaque ressource de fencing
+FR
+FR 2. positionner les stickiness de toutes les ressources à `1`
+FR 3. comparer l'évolution des scores
+FR 4. ajouter des contraintes d'exclusion pour que chaque ressource de fencing
+FR évite le nœud dont il est responsable. Utiliser un poids de 100 pour ces
+FR contraintes.
+FR 5. observer les changements de placement et de score par rapport à l'état
+FR précédent
+FR 6. afficher les contraintes existantes à l'aide de `pcs`
+FR
+1. display the score
+
+Check which node is responsible for each fencing resource.
+
+2. configure the stickiness of all resources to value of `1`
+3. compare the evolution of the scores
+4. add exclusion constraits to prevent each fencing resource from running on
+ the node it's tasked to fence. Use a weight of 100 for these constraints.
+5. watch out for the modification of the placement and score compared to the
+ previous state
+6. display the existing constraints with `pcs`
+
+:::
+
+-----
+
+### Correction: Location constraint creation
+
+::: notes
+
+FR 1. afficher les scores au sein du cluster
+FR
+1. display the score
+
+~~~console
+# crm_simulate --show-scores --live-check
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode3
+
+Allocation scores:
+native_color: fence_vm_hanode1 allocation score on hanode1: 0
+native_color: fence_vm_hanode1 allocation score on hanode2: 0
+native_color: fence_vm_hanode1 allocation score on hanode3: 0
+native_color: fence_vm_hanode2 allocation score on hanode1: 0
+native_color: fence_vm_hanode2 allocation score on hanode2: 0
+native_color: fence_vm_hanode2 allocation score on hanode3: 0
+native_color: fence_vm_hanode3 allocation score on hanode1: 0
+native_color: fence_vm_hanode3 allocation score on hanode2: 0
+native_color: fence_vm_hanode3 allocation score on hanode3: 0
+
+Transition Summary:
+~~~
+
+FR Ici, `fence_vm_hanode1` est surveillé depuis `hanode1`, `fence_vm_hanode2`
+FR depuis `hanode2` et `fence_vm_hanode3` depuis `hanode3`.
+FR
+Here, `fence_vm_hanode1` is monitored from `hanode1`, `fence_vm_hanode2` from
+`hanode2` and `fence_vm_hanode3` from `hanode3`.
+
+FR 2. positionner les stickiness de toutes les ressources à `1`
+FR
+2. configure the stickiness of all resources to value of `1`
+
+~~~console
+# pcs resource defaults resource-stickiness=1
+~~~
+
+FR 3. comparer l'évolution des scores
+FR
+3. compare the evolution of the scores
+~~~console
+# crm_simulate -sL
+[...]
+Allocation scores:
+native_color: fence_vm_hanode1 allocation score on hanode1: 1
+native_color: fence_vm_hanode1 allocation score on hanode2: 0
+native_color: fence_vm_hanode1 allocation score on hanode3: 0
+native_color: fence_vm_hanode2 allocation score on hanode1: 0
+native_color: fence_vm_hanode2 allocation score on hanode2: 1
+native_color: fence_vm_hanode2 allocation score on hanode3: 0
+native_color: fence_vm_hanode3 allocation score on hanode1: 0
+native_color: fence_vm_hanode3 allocation score on hanode2: 0
+native_color: fence_vm_hanode3 allocation score on hanode3: 1
+~~~
+
+FR Le score de chaque ressource a augmenté de `1` pour le nœud sur lequel
+FR elle est "démarrée".
+FR
+The score for each resource is increased by `1` on the node where it's started.
+
+FR 4. ajouter des contraintes d'exclusion pour que chaque ressource de fencing
+FR évite le nœud dont il est responsable. Utiliser un poids de 100 pour ces
+FR contraintes.
+FR
+4. add exclusion constraits to prevent each fencing resource from running on
+ the node it's tasked to fence. Use a weight of 100 for these constraints.
+
+~~~console
+# pcs constraint location fence_vm_hanode1 avoids hanode1=100
+# pcs constraint location fence_vm_hanode2 prefers hanode2=-100
+# pcs constraint location fence_vm_hanode3 avoids hanode3=100
+~~~
+
+FR Notez que les deux syntaxes proposées sont équivalentes du point de vue du
+FR résultat dans la CIB.
+FR
+Note that the two syntaxes are equivalent from the point of view of the result
+in the CIB.
+
+~~~
+# cibadmin -Q --xpath='//rsc_location'
+~~~
+
+FR 5. observer les changements de placement et de score par rapport à l'état
+FR précédent
+FR
+5. watch out for the modification of the placement and score compared to the
+ previous state
+
+~~~console
+# crm_simulate -sL
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+
+Allocation scores:
+native_color: fence_vm_hanode1 allocation score on hanode1: -100
+native_color: fence_vm_hanode1 allocation score on hanode2: 1
+native_color: fence_vm_hanode1 allocation score on hanode3: 0
+native_color: fence_vm_hanode2 allocation score on hanode1: 1
+native_color: fence_vm_hanode2 allocation score on hanode2: -100
+native_color: fence_vm_hanode2 allocation score on hanode3: 0
+native_color: fence_vm_hanode3 allocation score on hanode1: 1
+native_color: fence_vm_hanode3 allocation score on hanode2: 0
+native_color: fence_vm_hanode3 allocation score on hanode3: -100
+
+Transition Summary:
+~~~
+
+FR Chaque ressource a changé de nœud afin de ne plus résider sur celui qu'elle
+FR doit éventuellement isoler.
+FR
+FR Un score négatif de `-100` correspondant à la contrainte créée est positionné
+FR pour chaque ressource sur le nœud qu'elle doit éventuellement isoler.
+FR
+
+Each resource has changed node in order to avoid being hosted on the node they are
+tasked to isolate. A negative score of `-100` corresponding to the constraint
+is positionned for each resource on the relevant node.
+
+FR 6. afficher les contraintes existantes à l'aide de `pcs`
+FR
+6. display the existing constraints with `pcs`
+
+~~~console
+# pcs constraint location show
+Location Constraints:
+ Resource: fence_vm_hanode1
+ Disabled on: hanode1 (score:-100)
+ Resource: fence_vm_hanode2
+ Disabled on: hanode2 (score:-100)
+ Resource: fence_vm_hanode3
+ Disabled on: hanode3 (score:-100)
+
+# pcs constraint location show nodes
+Location Constraints:
+ Node: hanode1
+ Not allowed to run:
+ Resource: fence_vm_hanode1 (location-fence_vm_hanode1-hanode1--100) Score: -100
+ Node: hanode2
+ Not allowed to run:
+ Resource: fence_vm_hanode2 (location-fence_vm_hanode2-hanode2--100) Score: -100
+ Node: hanode3
+ Not allowed to run:
+ Resource: fence_vm_hanode3 (location-fence_vm_hanode3-hanode3--100) Score: -100
+
+# pcs constraint location show resources fence_vm_hanode1
+Location Constraints:
+ Resource: fence_vm_hanode1
+ Disabled on: hanode1 (score:-100)
+~~~
+
+:::
+
+-----
+
+## Création d'une ressource
+
+* nécessite:
+ * un identifiant
+ * le type/fournisseur/_RA_ à utiliser
+* et éventuellement:
+ * les paramètres propres à l'agent
+ * le paramétrage de [Méta-attributs des ressources]
+ * une configuration propre à chaque opérations
+* détails sur les timeouts
+
+::: notes
+
+Chaque ressource créée au sein du cluster doit avoir un identifiant unique à
+de votre choix.
+
+Vous devez ensuite indiquer le _resource agent_ adapté à la ressource que vous
+souhaitez intégrer dans votre cluster. Ce dernier est indiqué dans le format
+`type:nom` ou `type:fournisseur:nom`, par exemple: `systemd:pgbouncer`
+ou `ocf:heartbeat:Dummy`. La liste complète est disponible grâce à la commande
+`pcs resource list`.
+
+Voici un exemple simple de création d'une ressource avec `pcs`:
+
+~~~console
+# pcs resource create identifiant_resource type:fournisseur:nom
+~~~
+
+Ensuite Chaque _resource agent_ peut avoir des paramètres de configuration
+propre à sa ressource, un nom d'utilisateur par exemple. Avec `pcs`, ces
+paramètres sont à préciser librement à la suite de la commande de base, par
+exemple:
+
+~~~console
+# pcs resource create identifiant_resource type:fournisseur:nom \
+ user=nom_user_resource
+~~~
+
+Pour rappel, la liste des paramètres supportés par un _resource agent_ est
+disponible grâce à la commande suivante:
+
+~~~console
+# pcs resource describe
+~~~
+
+Comme détaillé dans le chapitre [Méta-attributs des ressources][], les
+ressources ont en commun un certain nombre de méta-attributs qui peuvent être
+modifiés pour chaque ressource. La commande `pcs` utilise le mot clé `meta`
+pour les distinguer sur la ligne de commande des autres paramètres. Par
+exemple, nous pouvons positionner `migration-threshold=1` sur une ressource
+afin qu'elle soit migrée sur un autre nœud dès la première erreur:
+
+~~~console
+# pcs resource create identifiant_resource type:fournisseur:nom \
+ user=nom_user_resource \
+ meta migration-threshold=1
+~~~
+
+Enfin, un certain nombre de paramètres peuvent être modifiés pour chaque
+opération supportée par le _RA_. Les plus fréquents sont `timeout`et
+`interval`. Vous trouverez la liste complète à l'adresse suivante:
+
+
+Concernant le timeout par exemple, ce dernier est de 20 secondes par défaut
+pour toutes les opérations. Cette valeur par défaut peut être modifiée dans la
+section `op_defaults` de la CIB, avec l'une ou l'autre de ces commandes:
+
+~~~
+crm_attribute --type op_defaults --name timeout --update 20s
+pcs resource op defaults timeout=20s
+~~~
+
+Avec la commande `pcs` nous utilisons le mot clé `op ` pour définir
+le paramétrage des différentes opérations. Le paramétrage pour ces actions
+surcharge alors les valeurs par défaut. Voici un exemple:
+
+~~~
+# pcs resource create identifiant_resource type:fournisseur:nom \
+ user=nom_user_resource \
+ meta migration-threshold=1 \
+ op start timeout=60s
+ op monitor timeout=10s interval=10s
+~~~
+
+__ATTENTION__: les valeurs par défaut exposées par les _RA_ sont des valeurs
+__recommandées__. Elles ne sont pas appliquées automatiquement. Préciser les
+timeouts de chaque action lors de la définition d'une ressource est recommandé
+même s'ils sont identiques à la valeur par défaut. Cette pratique aide à la
+compréhension rapide de la configuration d'un cluster.
+
+Les _resource agent_ n'ont pas à se préoccuper des timeout de leurs actions.
+Tout au plus, ces agents peuvent indiquer des timeout par défaut à titre de
+recommandation seulement. Il reste à la charge de l'administrateur de définir
+les différents timeout en tenant compte de cette recommandation.
+
+Le daemon `execd`, qui exécute l'action, se charge d'interrompre une action dès
+que son timeout est atteint. Habituellement, le cluster planifie alors des
+actions palliatives à cette erreur (eg. _recovery_ ou _failover_).
+
+:::
+
+-----
+
+### TP: création d'une ressource dans le cluster
+
+::: notes
+
+Création d'une première ressource "Dummy". Ce _resource agent_ existe
+seulement à titre de démonstration et d'expérimentation.
+
+1. afficher les détails de l'agent Dummy
+2. créer le sous-répertoire `/opt/sub` sur les 3 nœuds.
+3. créer une ressource `dummy1` utilisant le _RA_ Dummy
+
+Il est possible de travailler sur un fichier XML offline en précisant
+l'argument `-f /chemin/vers/xml` à la commande `pcs`. Utiliser un fichier
+`dummy1.xml` pour créer la ressource et ses contraintes en une seule
+transition.
+
+* positionner le paramètre `state` à la valeur `/opt/sub/dummy1.state`
+* vérifier son état toutes les 10 secondes
+* positionner son attribut `migration-threshold` à `3`
+* positionner son attribut `failure-timeout` à `4h`
+* positionner un `stickiness` faible de `1`
+* ajouter une forte préférence de `100` pour le nœud hanode1
+
+Tout ce paramétrage doit être en surcharge des éventuelles valeurs par
+défaut du cluster.
+
+4. contrôler le contenu du fichier `dummy1.xml` et simuler son application
+ avec `crm_simulate`
+5. publier les modifications dans le cluster
+6. consulter les logs du DC
+7. observer les changements opérés
+
+:::
+
+-----
+
+### Correction: création d'une ressource dans le cluster
+
+::: notes
+
+
+1. afficher les détails de l'agent Dummy
+
+~~~console
+# pcs resource describe ocf:pacemaker:Dummy
+~~~
+
+2. créer le sous-répertoire `/opt/sub` sur les 3 nœuds.
+
+Sur chaque nœud:
+
+~~~console
+# mkdir -p /opt/sub
+~~~
+
+3. créer une ressource `dummy1` utilisant le _RA_ Dummy
+
+~~~console
+# pcs cluster cib dummy1.xml
+
+# pcs -f dummy1.xml resource create dummy1 ocf:pacemaker:Dummy \
+ state=/opt/sub/dummy1.state \
+ op monitor interval=10s \
+ meta migration-threshold=3 \
+ meta failure-timeout=4h \
+ meta resource-stickiness=1
+
+# pcs -f dummy1.xml constraint location dummy1 prefers hanode1=100
+~~~
+
+4. contrôler le contenu du fichier `dummy1.xml` et simuler son application
+avec `crm_simulate`
+
+Contrôle de la syntaxe:
+
+~~~console
+# crm_verify -V --xml-file dummy1.xml
+# pcs cluster verify -V dummy1.xml # alternative avec pcs
+~~~
+
+Simuler ces modifications:
+
+~~~
+# crm_simulate --simulate --xml-file dummy1.xml
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ dummy1 (ocf::pacemaker:Dummy): Stopped
+
+Transition Summary:
+ * Start dummy1 ( hanode1 )
+
+Executing cluster transition:
+ * Resource action: dummy1 monitor on hanode3
+ * Resource action: dummy1 monitor on hanode2
+ * Resource action: dummy1 monitor on hanode1
+ * Resource action: dummy1 start on hanode1
+ * Resource action: dummy1 monitor=10000 on hanode1
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ dummy1 (ocf::pacemaker:Dummy): Started hanode1
+~~~
+
+Nous observons dans cette sortie:
+
+* l'état du cluster avant la transition (`Current cluster status`)
+* les actions à réaliser (`Transition Summary` et `Executing cluster transition`)
+* l'état attendu du cluster après transition (`Revised cluster status`)
+
+5. publier les modifications dans le cluster
+
+~~~
+# pcs cluster cib-push dummy1.xml
+~~~
+
+6. consulter les logs du DC
+
+Les log ont été remis en forme.
+
+Actions prévues par `pengine`:
+
+~~~
+pengine: info: RecurringOp: Start recurring monitor (10s) for dummy1 on hanode1
+pengine: info: LogActions: Leave fence_vm_hanode1 (Started hanode2)
+pengine: info: LogActions: Leave fence_vm_hanode2 (Started hanode1)
+pengine: info: LogActions: Leave fence_vm_hanode3 (Started hanode1)
+pengine: notice: LogAction: * Start dummy1 ( hanode1)
+pengine: notice: Calculated transition 21, saving in /.../pengine/pe-input-11.bz2
+~~~
+
+Actions initiées par `crmd`:
+
+~~~
+crmd: info: Processing graph 21 derived from /var/.../pengine/pe-input-11.bz2
+crmd: notice: Initiating monitor operation dummy1_monitor_0 on hanode3 | action 6
+crmd: notice: Initiating monitor operation dummy1_monitor_0 on hanode2 | action 5
+crmd: notice: Initiating monitor operation dummy1_monitor_0 locally on hanode1 | action 4
+crmd: info: Action dummy1_monitor_0 (5) confirmed on hanode2 (rc=7)
+crmd: info: Action dummy1_monitor_0 (6) confirmed on hanode3 (rc=7)
+crmd: info: Action dummy1_monitor_0 (4) confirmed on hanode1 (rc=7)
+crmd: notice: Result of probe operation for dummy1 on hanode1: 7 (not running)
+
+crmd: notice: Initiating start operation dummy1_start_0 locally on hanode1
+lrmd: info: executing - rsc:dummy1 action:start call_id:26
+lrmd: info: finished - rsc:dummy1 action:start call_id:26 exit-code:0
+crmd: notice: Result of start operation for dummy1 on hanode1: 0 (ok)
+
+crmd: notice: Initiating monitor operation dummy1_monitor_10000 locally on hanode1
+lrmd: debug: executing - rsc:dummy1 action:monitor call_id:27
+~~~
+
+Les actions `dummy1_monitor_0` vérifient que la ressource n'est démarrée pas
+démarrée sur le nœud concerné. Ensuite, la ressource est démarrée sur
+`hanode1` avec l'opération `dummy1_start_0`. Puis l'action de surveillance
+`dummy1_monitor_10000` récurrente toutes les 10 secondes (`10000`ms) est
+démarrée.
+
+7. observer les changements
+
+~~~console
+# pcs status
+# pcs config show
+~~~
+
+:::
+
+-----
+
+## Contraintes de colocation
+
+* définit un lien entre plusieurs ressources
+* la force du lien est définie par un score qui s'ajoute aux scores existant
+* peut être un lien de colocalisation ou d'exclusion
+ * Par exemple une VIP là où la ressource doit être démarrée
+* attention à l'ordre de déclaration !
+
+::: notes
+
+Les contraintes de colocation servent à indiquer à Pacemaker où une ressource _A_ doit
+être placée par rapport à une ressource _B_. Elles permettent de localiser deux ressources
+au même endroit ou à des endroits différents (exclusion).
+
+L'ordre des déclarations est important car cela implique que la ressource _A_ sera
+assignée à un nœud après la ressource _B_. Cela implique que la contrainte de
+localisation placée sur la ressource _B_ décide du placement de la ressource _A_.
+
+Ces contraintes n'ont pas d'impact sur l'[ordre de démarrage][Contraintes d'ordre].
+
+Dans le cas de PAF, il faut utiliser une contrainte de colocation pour que la VIP
+soit montée sur le même nœud que le master.
+
+[Explication](http://clusterlabs.org/doc/Colocation_Explained.pdf)
+
+:::
+
+-----
+
+### TP: création des _RA_ (dummy2) dans le cluster
+
+
+::: notes
+
+1. ajouter une ressource `dummy2`
+
+Utiliser un fichier `dummy2.xml` pour préparer les actions.
+
+* positionner le paramètre `state` à la valeur `/opt/sub/dummy2.state`
+* vérifier son état toutes les 10 secondes
+* positionner son attribut `migration-threshold` à `3`
+* positionner son attribut `failure-timeout` à `4h`
+* positionner un `stickiness` élevé de `100`
+* interdire la ressource de démarrer sur le même nœud que `dummy1`
+* ajouter une faible préférence de `10` pour le nœud hanode2
+
+Note : il est important d'utiliser un fichier xml pour appliquer les contraintes de localisation avant de démarrer la
+ressource
+
+4. contrôler le contenu du fichier `dummy2.xml` et simuler son application
+5. publier les modifications dans le cluster
+6. observer les changements
+
+:::
+
+-----
+
+### Correction: création des _RA_ (dummy2) dans le cluster
+
+::: notes
+
+
+1. ajouter une ressource `dummy2`
+
+~~~console
+# pcs cluster cib dummy2.xml
+
+# pcs -f dummy2.xml resource create dummy2 ocf:pacemaker:Dummy \
+ state=/opt/sub/dummy2.state \
+ op monitor interval=10s \
+ meta migration-threshold=3 \
+ meta failure-timeout=4h \
+ meta resource-stickiness=100
+
+# pcs -f dummy2.xml constraint location dummy2 prefers hanode2=10
+
+# pcs -f dummy2.xml constraint colocation add dummy2 with dummy1 -INFINITY
+~~~
+
+4. contrôler le contenu du fichier `dummy2.xml` et simuler son application
+
+~~~console
+# pcs cluster verify -V dummy2.xml
+# crm_simulate -S -x dummy2.xml
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ dummy1 (ocf::pacemaker:Dummy): Started hanode1
+ dummy2 (ocf::pacemaker:Dummy): Stopped
+
+Transition Summary:
+ * Start dummy2 ( hanode3 )
+
+Executing cluster transition:
+ * Resource action: dummy2 monitor on hanode3
+ * Resource action: dummy2 monitor on hanode2
+ * Resource action: dummy2 monitor on hanode1
+ * Resource action: dummy2 start on hanode3
+ * Resource action: dummy2 monitor=10000 on hanode3
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ dummy1 (ocf::pacemaker:Dummy): Started hanode1
+ dummy2 (ocf::pacemaker:Dummy): Started hanode3
+~~~
+
+Ici, `pengine` a prévu de démarrer `dummy2` sur `hanode3`.
+
+5. publier les modifications dans le cluster
+
+~~~console
+# pcs cluster cib-push dummy2.xml
+~~~
+
+6. observer les changements opérés
+
+~~~console
+# crm_mon -Dn
+# pcs status
+# pcs config show
+~~~
+
+:::
+
+-----
+
+## Contraintes d'ordre
+
+* concerne des ressources liées
+* déclaration de l'ordre de déclenchement des actions
+ * `stop`
+ * `start`
+ * `promote`
+ * `demote`
+* ordre obligatoire, optionnel ou sérialisé
+* symétrique ou asymétrique
+
+::: notes
+
+Ce type de contrainte peut être nécessaire pour spécifier l'ordre de
+déclenchement des actions. Par exemple, le déplacement d'une IP virtuelle une
+fois que le service a été déplacé sur un autre nœud.
+
+Il existe trois type différents, précisé par l'attribut `kind` :
+
+* `Mandatory`: la seconde action n'est pas exécutée tant que la première
+ action n'a pas réussi
+* `Optional`: les deux actions peuvent être exécutées indépendamment, mais
+respecterons l'ordre imposé si elles doivent l'être dans la même transition
+* `Serialize`: les actions ne doivent pas être exécutées en même temps par
+ le cluster. L'ordre importe peu ici.
+
+Si une contrainte d'ordre est symétrique (attribut `symmetrical`), elle
+s'applique aussi pour les actions opposées, mais dans l'ordre inverse.
+
+:::
+
+
+-----
+
+### TP: Contrainte d'ordre
+
+::: notes
+
+Il est recommandé de conserver un terminal avec un `crm_mon` actif tout au long
+de ce TP.
+
+1. créer une contrainte d'ordre non symétrique qui force le démarrage de
+`dummy1` avant celui de `dummy2`
+2. arrêter la ressource `dummy1` et observer l'influence sur `dummy2`
+3. arrêter la ressource `dummy2`, puis démarrer `dummy2`
+4. démarrer `dummy1`
+5. vérifiez dans les log __du DC__ l'ordre des actions
+
+:::
+
+-----
+
+### Correction: Contrainte d'ordre
+
+::: notes
+
+Il est recommandé de conserver un terminal avec un `crm_mon` actif tout au long
+de ce TP.
+
+1. créer une contrainte d'ordre non symétrique qui force le démarrage de
+ `dummy1` avant celui de `dummy2`
+
+~~~console
+# pcs constraint order start dummy1 then start dummy2 symmetrical=false kind=Mandatory
+Adding dummy1 dummy2 (kind: Mandatory) (Options: first-action=start then-action=start symmetrical=false)
+~~~
+
+2. arrêter la ressource `dummy1` et observer l'influence sur `dummy2`
+
+~~~console
+# pcs resource disable dummy1
+~~~
+
+La ressource `dummy2` ne s'arrête pas. La contrainte ne concerne que le
+démarrage des deux ressources.
+
+3. arrêter la ressource `dummy2`, puis démarrer `dummy2`
+
+~~~console
+# pcs resource disable --wait dummy2
+# pcs resource enable dummy2
+~~~
+
+La ressource `dummy2` ne démarre pas. Cette dernière ne peut démarrer
+qu'après le démarrage de `dummy1`, mais cette dernière est arrêtée.
+
+4. démarrer `dummy1`
+
+~~~console
+# pcs resource enable dummy1
+~~~
+
+Les deux ressources démarrent.
+
+5. vérifiez dans les log __du DC__ l'ordre des actions
+
+Les log ont été remis en forme.
+
+~~~console
+# grep 'dummy._start.*confirmed' /var/log/cluster/corosync.log
+crmd: info: Action dummy1_start_0 (48) confirmed on hanode1 (rc=0)
+crmd: info: Action dummy2_start_0 (50) confirmed on hanode3 (rc=0)
+~~~
+
+L'ordre des action est précisé par leur ID, ici 48 et 50. Il est possible
+d'aller plus loin avec `crm_simulate` et ses options `-S`, `-G` et `-x` en
+indiquant la transition produite par `pengine` dans le répertoire
+`/var/lib/pacemaker/pengine`. Cette commande et analyse est laissée à
+l'exercice du lecteur.
+
+:::
+
+
+-----
+
+## Regroupement de ressources
+
+* "group" : regroupement de ressources liées ("primitives")
+* simplification de déclaration de contraintes de "colocation"
+* sont démarrées dans l'ordre de déclaration
+* sont arrêtées dans l'ordre inverse de déclaration
+* une impossibilité de démarrer une ressource affecte les ressources
+ suivantes dans le groupe
+
+::: notes
+
+La notion de groupe est un raccourcis syntaxique qui permet de simplifier les
+déclarations en regroupant les contraintes d'un ensemble de ressources.
+
+Les attributs d'un groupe permettent notamment de définir la priorité et le
+rôle du group ou encore de mettre l'ensemble du groupe en maintenance.
+
+La `stickiness` d'un groupe correspond à la somme des `stickiness` des ressources
+présentes dans ce groupe.
+
+Dans le cas de PAF, on utilise un groupe pour rassembler la ressource PostgreSQL
+master et la VIP.
+
+:::
+
+-----
+
+### TP: groupe de ressource
+
+::: notes
+
+1. créer une ressource `dummy3`
+
+Utiliser un fichier `dummy3.xml` pour préparer les actions.
+
+* positionner le paramètre `state` à la valeur `/opt/sub/dummy3.state`
+* vérifier son état toutes les 10 secondes
+* positionner son attribut `migration-threshold` à `3`
+* positionner son attribut `failure-timeout` à `4h`
+* positionner un `stickiness` élevé de `100`
+
+2. créer un group `dummygroup` qui regroupe les ressources `dummy3` et
+ `dummy2` dans cet ordre
+3. créer une contrainte d'ordre qui impose de démarrer `dummy1` avant `dummy3`
+4. créer une contrainte d'exclusion entre `dummygroup` et `dummy1` d'un score
+ de `-1000`
+5. appliquer les modifications au cluster
+6. désactiver les ressources `dummy1`, `dummy2` et `dummy3`, puis les
+ réactiver en même temps
+7. observer l'ordre choisi par pengine pour le démarrage de l'ensemble des ressources
+
+:::
+
+-----
+
+### Correction: groupe de ressource
+
+::: notes
+
+1. créer une ressource `dummy3`
+
+~~~console
+# pcs cluster cib dummy3.xml
+
+# pcs -f dummy3.xml resource create dummy3 ocf:pacemaker:Dummy \
+ state=/opt/sub/dummy3.state \
+ op monitor interval=10s \
+ meta migration-threshold=3 \
+ meta failure-timeout=4h \
+ meta resource-stickiness=100
+~~~
+
+2. créer un group `dummygroup` qui regroupe les ressources `dummy3` et `dummy2` dans cet ordre
+
+~~~console
+# pcs -f dummy3.xml resource group add dummygroup dummy3 dummy2
+~~~
+
+3. créer une contrainte d'ordre qui impose de démarrer `dummy1` avant `dummy3`
+
+~~~console
+# pcs -f dummy3.xml constraint order start dummy1 then start dummy3 symmetrical=false kind=Mandatory
+Adding dummy1 dummy3 (kind: Mandatory) (Options: first-action=start then-action=start symmetrical=false)
+~~~
+
+4. créer une contrainte d'exclusion entre `dummygroup` et `dummy1` d'un score
+ de `-1000`
+
+~~~console
+# pcs -f dummy3.xml constraint colocation add dummygroup with dummy1 -1000
+~~~
+
+5. appliquer les modifications au cluster
+
+~~~console
+# pcs cluster verify -V dummy3.xml
+# crm_simulate -S -x dummy3.xml
+
+# pcs cluster cib-push dummy3.xml
+CIB updated
+~~~
+
+6. désactiver les ressources `dummy1`, `dummy2` et `dummy3`, puis les
+ réactiver en même temps
+
+~~~
+# pcs resource disable --wait dummy1 dummy2 dummy3
+# pcs resource enable dummy1 dummy2 dummy3
+~~~
+
+7. observer l'ordre choisi par pengine pour le démarrage de l'ensemble des ressources
+
+Les ressources sont démarrés dans l'ordre suivant: `dummy1`, `dummy3` puis
+`dummy2`. Les log ont été remis en forme.
+
+~~~
+# grep 'dummy._start.*confirmed' /var/log/cluster/corosync.log
+crmd: info: Action dummy1_start_0 (10) confirmed on hanode1 (rc=0)
+crmd: info: Action dummy3_start_0 (12) confirmed on hanode3 (rc=0)
+crmd: info: Action dummy2_start_0 (14) confirmed on hanode3 (rc=0)
+~~~
+
+:::
+
+-----
+
+### TP: failcounts
+
+::: notes
+
+Nous provoquons dans ce TP une défaillance pour travailler dessus.
+
+1. renommer `/opt/sub` en `/opt/sub2` sur le nœud hébergeant `dummy1`
+
+Attendre que le cluster réagisse à la défaillance.
+
+2. observer le failcount de `dummy1` avec `crm_failcount` ou `pcs`
+3. chercher dans les log les causes de cette valeur
+4. réparer le problème sur `hanode1` et réinitialiser le failcount avec `pcs`
+5. expliquer le comportement de `dummy1`
+
+Conseil: observer les scores.
+
+:::
+
+-----
+
+### Correction: failcounts
+
+::: notes
+
+1. renommer `/opt/sub` en `/opt/sub2` sur le nœud hébergeant `dummy1`
+
+Observer le cluster et ses réactions dans un terminal à l'aide de `crm_mon`:
+
+~~~console
+# crm_mon -Dnf
+~~~
+
+Renommer le répertoire pour provoquer une défaillance:
+
+~~~console
+# mv /opt/sub /opt/sub2
+~~~
+
+Attendre que le cluster réagisse à la défaillance.
+
+2. observer le failcount de `dummy1` avec `crm_failcount` ou `pcs`
+
+~~~console
+# crm_failcount -r dummy1 -N hanode1 -G
+scope=status name=fail-count-dummy1 value=INFINITY
+
+# crm_failcount -r dummy1 -N hanode3 -G
+scope=status name=fail-count-dummy1 value=0
+
+# pcs resource failcount show dummy1
+Failcounts for dummy1
+hanode1: INFINITY
+~~~
+
+3. chercher dans les log les causes de cette valeur
+
+Rechercher dans les log du DC les mots clé `failcount` et `dummy1` pour
+identifier les messages relatifs à cette activité. Ci-après une explication
+des log remis en forme.
+
+Détection de l'erreur lors d'une opération `monitor` et incrément du
+failcount pour la ressource sur le nœud où elle se situe:
+
+~~~
+crmd: info: Updating failcount for dummy1 on hanode1 after failed monitor: rc=7 (update=value++)
+attrd: info: Expanded fail-count-dummy1#monitor_10000=value++ to 1
+attrd: info: Setting fail-count-dummy1#monitor_10000[hanode1]: (null) -> 1
+~~~
+
+Calcul d'une transition afin de rétablir un état stable du cluster. Le
+sous-processus `pengine` prévoit de redémarrer `dummy1` sur son nœud courant:
+
+~~~
+pengine: info: Start recurring monitor (10s) for dummy1 on hanode1
+pengine: notice: * Recover dummy1 ( hanode1)
+pengine: info: Leave dummy3 (Started hanode2)
+pengine: info: Leave dummy2 (Started hanode2)
+~~~
+
+Ce choix dépend de la propriété `on-fail` de l'opération, à `restart` par
+défaut. Pour plus de détail, voir:
+
+
+L'action `recovery` consiste a arrêter et démarrer la ressource concernée.
+Une fois l'opération `stop` réalisée, nous observons que le `start` échoue.
+
+~~~
+crmd: notice: te_rsc_command: Initiating stop operation dummy1_stop_0 on hanode1
+crmd: info: match_graph_event: Action dummy1_stop_0 (6) confirmed on hanode1 (rc=0)
+crmd: notice: te_rsc_command: Initiating start operation dummy1_start_0 on hanode1
+crmd: warning: status_from_rc: Action 14 (dummy1_start_0) on hanode1 failed (target: 0 vs. rc: 1): Error
+crmd: notice: abort_transition_graph: Transition aborted by operation dummy1_start_0 'modify' on hanode1: Event failed
+crmd: info: update_failcount: Updating failcount for dummy1 on hanode1 after failed start: rc=1 (update=INFINITY)
+attrd: info: attrd_peer_update: Setting fail-count-dummy1#start_0[hanode1]: (null) -> INFINITY
+~~~
+
+Si une opération `start` échoue, la décision du cluster dépend de deux
+paramètres: `on-fail` que nous avons vu précédemment et le paramètre du
+cluster `start-failure-is-fatal`, positionné à `true` par défaut.
+
+Ici, l'opération `start` ayant échoué, le cluster décide donc de
+positionner un failcount à INFINITY à cause de `start-failure-is-fatal`.
+
+La ressource `dummy1` ayant un failcount infini sur `hanode1`, `pengine`
+décide de déplacer la ressource sur `hanode3`:
+
+~~~
+pengine: info: Start recurring monitor (10s) for dummy1 on hanode3
+pengine: notice: * Recover dummy1 (hanode1 -> hanode3)
+pengine: info: Leave dummy3 (Started hanode2)
+pengine: info: Leave dummy2 (Started hanode2)
+~~~
+
+Les opérations sont réalisées sans erreurs:
+
+~~~
+crmd: debug: Unpacked transition 22: 3 actions in 3 synapses
+[...]
+crmd: notice: Initiating stop operation dummy1_stop_0 on hanode1
+crmd: info: Action dummy1_stop_0 confirmed on hanode1 (rc=0)
+[...]
+crmd: notice: Initiating start operation dummy1_start_0 on hanode3
+crmd: info: Action dummy1_start_0 confirmed on hanode3 (rc=0)
+[...]
+crmd: notice: Initiating monitor operation dummy1_monitor_10000 on hanode3
+crmd: info: Action dummy1_monitor_10000 confirmed on hanode3 (rc=0)
+[...]
+crmd: debug: Transition 22 is now complete
+~~~
+
+4. réparer le problème sur `hanode1` et réinitialiser le failcount avec `pcs`
+
+~~~console
+# mv /opt/sub2 /opt/sub
+# pcs resource failcount reset dummy1 hanode1
+~~~
+
+5. expliquer le comportement de `dummy1`
+
+La ressource `dummy1` retourne sur le nœud `hanode1` dès que nous y
+supprimons son ancien failcount.
+
+Effectivement, `dummy1` a été créé avec un `stickiness` à `1` et une
+contrainte de location sur `hanode1` de `100`.
+
+~~~
+# pcs constraint location show dummy1
+Location Constraints:
+ Resource: dummy1
+ Enabled on: hanode1 (score:100)
+[...]
+
+# pcs resource show dummy1
+ Resource: dummy1 (class=ocf provider=pacemaker type=Dummy)
+ Attributes: state=/opt/sub/dummy1.state
+ Meta Attrs: failure-timeout=4h migration-threshold=3 resource-stickiness=1
+[...]
+~~~
+
+Avant de retirer son failcount sur `hanode1`, ses scores étaient les suivants:
+
+~~~
+native_color: dummy1 allocation score on hanode1: -INFINITY
+native_color: dummy1 allocation score on hanode2: -220
+native_color: dummy1 allocation score on hanode3: 1
+~~~
+
+Sur `hanode1`, `dummy1` cumulait le score de location de `100` et le failcount de
+`-INFINITY`, soit un total de `-INFINITY`. Le score de `1` correspondant au
+stickiness sur `hanode3`.
+
+Après la suppression du failcount de -INFINITY, les scores sont donc devenus:
+
+* `100` pour `dummy1` sur `hanode1` (score de location)
+* `1` pour `dummy1` sur `hanode3` (score de stickiness)
+
+Par conséquent `pengine` décide de déplacer `dummy1` sur le nœud où il a
+le plus gros score: `hanode1`. Après migration, les scores deviennent alors:
+
+~~~
+native_color: dummy1 allocation score on hanode1: 101
+native_color: dummy1 allocation score on hanode2: -220
+native_color: dummy1 allocation score on hanode3: 0
+~~~
+
+:::
+
+-----
+
+## Édition des ressources
+
+* la modification d'un paramètre provoque une réaction du cluster
+* soit le redémarrage de la ressource
+* soit son rechargement à chaud
+* dépend de la ressource et du paramètre
+
+::: notes
+
+La configuration des ressources peut être faite avec `pcs resource update` ou
+avec l'outil `crm_resource` et l'option `-s / --set-parameter` ou `-d /
+--delete-parameter`.
+
+On distingue les paramètres de :
+
+* configuration propre à la ressource, les paramètres propres à chaque RA
+* configuration du RA, les paramètres communs à tous les RA (modifiable avec l'option --meta)
+* configuration des opérations.
+
+Un paramètre propre à la ressource est modifiable à chaud si:
+
+* l'agent supporte l'action `reload`
+* ce paramètre n'est pas marqué comme étant `unique`
+
+:::
+
+-----
+
+### TP: modification paramètre avec reload ou restart
+
+::: notes
+
+1. afficher la description du RA `ocf:pacemaker:Dummy`
+2. identifier dans la description le paramètre `fake`
+3. afficher la valeur actuelle du paramètre `fake`
+4. modifier la valeur de `fake` avec `test`
+5. vérifier le comportement dans les traces
+
+Notes: utilisez `crm_resource` ou `pcs resource`
+
+:::
+
+-----
+
+### Correction: modification paramètre avec reload ou restart
+
+::: notes
+
+1. afficher la description du RA `ocf:pacemaker:Dummy`
+
+~~~console
+# pcs resource describe ocf:pacemaker:Dummy
+~~~
+
+2. identifier dans la description le paramètre `fake`
+
+~~~
+[...]
+ fake: Fake attribute that can be changed to cause a reload
+[...]
+~~~
+
+3. afficher la valeur actuelle du paramètre `fake`
+
+~~~console
+# crm_resource -r dummy1 -g fake
+Attribute 'fake' not found for 'dummy1'
+~~~
+
+4. modifier la valeur de `fake` avec `test`
+
+~~~console
+# crm_resource -r dummy1 -p fake -v test
+~~~
+
+ou
+
+~~~console
+# pcs resource update dummy1 fake=test
+~~~
+
+5. vérifier le comportement dans les traces
+
+Log du DC remis en forme:
+
+~~~
+pengine: info: Start recurring monitor (10s) for dummy1 on hanode1
+pengine: notice: * Reload dummy1 (hanode1)
+[...]
+crmd: debug: Unpacked transition 34: 2 actions in 2 synapses
+[...]
+crmd: notice: Initiating reload operation dummy1_reload_0 on hanode1
+crmd: info: Action dummy1_start_0 confirmed on hanode1
+[...]
+crmd: notice: Initiating monitor operation dummy1_monitor_10000 on hanode1
+crmd: info: Action dummy1_monitor_10000 confirmed on hanode1
+[...]
+crmd: notice: Transition 34 (Complete=2): Complete
+~~~
+
+Log de `hanode1`:
+
+~~~
+crmd: debug: Cancelling op 55 for dummy1
+lrmd: info: Cancelling ocf operation dummy1_monitor_10000
+lrmd: debug: finished - rsc:dummy1 action:monitor call_id:55 exit-code:0
+crmd: debug: Op 55 for dummy1 (dummy1:55): cancelled
+[...]
+crmd: info: Performing key=7:34:0:cc37b9f1-860c-4a1f-bbac-db48f7cd080a op=dummy1_reload_0
+lrmd: info: executing - rsc:dummy1 action:reload call_id:57
+lrmd: info: finished - rsc:dummy1 action:reload call_id:57 pid:13714 exit-code:0 exec-time:69ms queue-time:0ms
+crmd: notice: Result of reload operation for dummy1 on hanode1: 0 (ok)
+[...]
+crmd: info: Performing key=3:34:0:cc37b9f1-860c-4a1f-bbac-db48f7cd080a op=dummy1_monitor_10000
+lrmd: debug: executing - rsc:dummy1 action:monitor call_id:58
+lrmd: debug: finished - rsc:dummy1 action:monitor call_id:58 pid:13722 exit-code:0 exec-time:30ms queue-time
+crmd: info: Result of monitor operation for dummy1 on hanode1: 0 (ok)
+~~~
+
+:::
+
+
+-----
+
+## Ressources _Multi-State_
+
+* les ressource multi-state sont des clones avec des rôles différents
+* nécessite de configurer un `monitor` distinct par rôle
+* une ressource supplémentaire dédiée à la gestion des clones et leurs rôles
+* nombre de clones modifiable
+* les clones démarrent toujours d'abord en `Slave`
+* les master score permettent de désigner le ou les clones à promouvoir
+
+::: notes
+
+Comme expliqué dans le chapitre [_Ressource Agent_ (_RA_)] il existe
+plusieurs type de ressources, dont les ressources clones ou les ressources
+_multi-state_. Ces derniers héritent de toutes les propriétés des ressources
+clones et ajoute une notion supplémentaire de rôle primaire et secondaire
+appelés respectivement `Master` et `Slave`.
+
+Une ressource _multi-state_ se crée en deux étapes:
+
+* création d'une ressource type utilisant le RA voulu
+* création d'une ressource _multi-state_ qui administre la ressource précédemment
+ créée, la clone en fonction de sa configuration et gère les rôles parmi
+ ces clones.
+
+Particularité des ressources géré en _muti-state_, ces dernières doivent
+comporter une opération `monitor` différente pour les rôles `Slave` et
+`Master`, chacune avec une récurrence différente. Ce dernier point est lié à un
+détail d'implémentation de Pacemaker qui identifie les opérations par un
+identifiant composé: du nom de la ressource, de l'opération, de sa récurrence.
+Ainsi, `pgsqld_monitor_15000` désigne l'opération `monitor` sur la ressource
+`pgsqld` exécutée toute les 15 secondes. Voir:
+
+
+
+Les différents paramètres utiles à une ressource _multi-state_ sont définis dans
+la documentation de Pacemaker à ces pages:
+
+* liés aux clones:
+* liés aux _multi-state_:
+
+Les paramètres intéressants dans le cadre de cette formation sont:
+
+* `clone-max`: nombre de clones dans tous le cluster, par défaut le nombre de
+ nœud du cluster
+* `clone-node-max`: nombre de clone maximum sur chaque nœud, par défaut à `1`
+* `master-max`: nombre maximum de clone promu au sein du cluster, par défaut
+ à `1`
+* `master-node-max`: nombre maximum de clone promu sur chaque nœud, par
+ défaut à `1`
+* `notify`: activer les opérations `notify` si le RA le supporte, par défaut
+ à `false`
+
+Nous constatons que la plupart des valeurs par défaut sont correcte pour PAF.
+Seule le paramètre `notify` doit être __obligatoire__ activé dans le cadre
+de PAF.
+
+Enfin, tous les clones d'une ressource multi-state sont __toujours__ démarrés
+avec le rôle `Slave`. Ensuite, les clones avec les _master scores_ les plus
+élevés sont sélectionnés pour être promus en `Master` (voir aussi à ce propos
+[Attributs de nœuds particuliers] ).
+
+
+
+Ces master scores sont positionnés le plus souvent par le RA, mais peuvent
+aussi être manipulés par l'administrateur si besoin.
+
+:::
+
+-----
+
+::: notes
+
+### TP: création d'une ressource _multi-state_
+
+Utiliser un fichier `dummy-ms.xml` pour effectuer vos modifications.
+
+1. créer une ressource `Dummyd` avec le RA `ocf:pacemaker:Stateful`
+
+* surveiller le rôle `Master` toutes les 5 secondes
+* surveiller le rôle `slave` toutes les 6 secondes
+
+2. créer la ressource multi-state `Dummyd-clone` clonant `Dummyd`
+
+* activer les notifications
+* dix clones autorisés
+* deux rôles `Master` autorisés
+
+3. appliquer vos modifications sur le cluster
+4. expliquer le nombre de clone de `Dummyd` démarrés
+5. observer combien de clones ont été promus en `Master`
+
+:::
+
+-----
+
+### Correction: création d'une ressource _multi-state_
+
+::: notes
+
+Utiliser un fichier `dummy-ms.xml` pour effectuer vos modifications.
+
+~~~console
+# pcs cluster cib dummy-ms.xml
+~~~
+
+1. créer une ressource `Dummyd` avec le RA `ocf:pacemaker:Stateful`
+
+~~~console
+# pcs -f dummy-ms.xml resource create Dummyd ocf:pacemaker:Stateful \
+ op monitor interval=5s role="Master" \
+ op monitor interval=6s role="Slave"
+~~~
+
+2. créer la ressource multi-state `Dummyd-clone` clonant `Dummyd`
+
+* activer les notifications
+* dix clones autorisés
+* deux rôles `Master` autorisés
+
+Ou, en tenant compte des valeurs par défaut:
+
+~~~console
+# pcs -f dummy-ms.xml resource master Dummyd-clone Dummyd \
+ notify=true clone-max=10 master-max=2
+~~~
+
+3. appliquer vos modifications sur le cluster
+
+~~~console
+# pcs cluster verify -V dummy-ms.xml
+# crm_simulate -S -x dummy-ms.xml
+# pcs cluster cib-push dummy-ms.xml
+~~~
+
+4. expliquer le nombre de clone de `Dummyd` démarrés
+
+Trois clones ont été démarrés dans le cluster. Malgré la valeur de
+`clone-max=10`, le paramètre `clone-node-max` par défaut à `1` empêche d'en
+démarrer plus d'un par nœud.
+
+~~~
+pengine: debug: Allocating up to 10 Dummyd-clone instances to a possible 3 nodes (at most 1 per host, 3 optimal)
+pengine: debug: Assigning hanode3 to Dummyd:0
+pengine: debug: Assigning hanode2 to Dummyd:1
+pengine: debug: Assigning hanode1 to Dummyd:2
+pengine: debug: All nodes for resource Dummyd:3 are unavailable, unclean or shutting down
+pengine: debug: Could not allocate a node for Dummyd:3
+pengine: info: Resource Dummyd:3 cannot run anywhere
+[...]
+pengine: debug: All nodes for resource Dummyd:9 are unavailable, unclean or shutting down
+pengine: debug: Could not allocate a node for Dummyd:9
+pengine: info: Resource Dummyd:9 cannot run anywhere
+pengine: debug: Allocated 3 Dummyd-clone instances of a possible 10
+~~~
+
+5. observer combien de clones ont été promus en `Master`
+
+Deux clones ont été promus.
+
+Lors du démarrage des instances `Dummyd`, l'agent positionne le master score
+de sa ressource à `5`. Voir la fonction `stateful_start` dans le code source
+de l'agent à l'emplacement `/usr/lib/ocf/resource.d/pacemaker/Stateful`.
+
+Le paramètre `master-max` étant positionné à `2`, le cluster choisi deux
+clones à promouvoir parmis les trois disponibles.
+
+:::
+
+-----
+
+## Suppression des ressources
+
+* `pcs resource delete` supprime une ressource ou un groupe
+* deux étapes :
+ * stopper la ressource
+ * supprimer la ressource
+
+::: notes
+
+La supression de ressource peut être réalisée par `pcs resource delete
+`.
+
+La supression d'un groupe supprime non seulement ce groupe mais aussi les
+ressources qu'il contient.
+
+:::
+
+-----
+
+### TP: supprimer les dummy
+
+::: notes
+
+1. lister les ressources du cluster
+2. supprimer les ressources `dummy1` et `dummy2`
+3. afficher l'état du cluster
+4. supprimer le groupe `dummygroup`
+5. afficher l'état du cluster
+6. supprimer la ressource `Dummyd-clone`
+7. afficher l'état du cluster
+
+:::
+
+-----
+
+### Correction: supprimer les dummy
+
+::: notes
+
+1. lister les ressources du cluster
+
+~~~console
+# pcs resource show
+ Master/Slave Set: Dummyd-clone [Dummyd]
+ Masters: [ hanode1 hanode2 ]
+ Slaves: [ hanode3 ]
+ dummy1 (ocf::pacemaker:Dummy): Started hanode1
+ Resource Group: dummygroup
+ dummy3 (ocf::pacemaker:Dummy): Started hanode2
+ dummy2 (ocf::pacemaker:Dummy): Started hanode2
+
+
+~~~
+
+2. supprimer les ressources `dummy1` et `dummy2`
+
+~~~console
+# pcs resource delete dummy1
+Attempting to stop: dummy1... Stopped
+# pcs resource delete dummy2
+Attempting to stop: dummy2... Stopped
+~~~
+
+3. afficher l'état du cluster
+
+~~~console
+# pcs resource show
+ Master/Slave Set: Dummyd-clone [Dummyd]
+ Masters: [ hanode1 hanode2 ]
+ Slaves: [ hanode3 ]
+ Resource Group: dummygroup
+ dummy3 (ocf::pacemaker:Dummy): Started hanode2
+
+~~~
+
+4. supprimer le groupe dummygroup
+
+~~~console
+# pcs resource delete dummygroup
+Removing group: dummygroup (and all resources within group)
+Stopping all resources in group: dummygroup...
+Deleting Resource (and group) - dummy3
+~~~
+
+5. afficher l'état du cluster
+
+~~~console
+# pcs resource show
+ Master/Slave Set: Dummyd-clone [Dummyd]
+ Masters: [ hanode1 hanode2 ]
+ Slaves: [ hanode3 ]
+~~~
+
+6. supprimer la ressource `Dummyd-clone`
+
+~~~console
+# pcs resource delete Dummyd-clone
+Attempting to stop: Dummyd... Stopped
+~~~
+
+7. afficher l'état du cluster
+
+~~~console
+# pcs resource show
+NO resources configured
+~~~
+
+:::
+
+-----
+
+## Règles
+
+* possibilité de modifier les contraintes selon des conditions
+ * par exemple une plage horaire
+
+::: notes
+
+Les règles permettent de définir :
+
+* les contraintes de localisation ,
+* les options et attributs d'instance d'une ressource ,
+* les options du cluster ,
+
+en fonction :
+
+* des attributs d'un nœud ,
+* de l'heure, de la date ou de la périodicité (à la manière d'une crontab) ,
+* d'une durée.
+
+Pacemaker recalcule l'état du cluster sur la base d'évènements. Il est possible
+qu'aucun évènement ne se produise pendant une période, ce qui empêcherait le
+déclenchement d'une modification de configuration lié à une règle temporelle.
+Il faut donc configurer le paramètre `cluster-recheck-interval` a une valeur adaptée
+pour s'assurer que les règles basées sur le temps soient exécutées.
+
+Les versions récentes de Pacemaker (à partir de la version 2.0.3) sont plus
+fines à ce propos. Le `cluster-recheck-interval` est calculé dynamiquement en
+fonction des contraintes, règles et différents timeout existants, à une
+exception près. Voir à ce propos:
+
+
+Les règles peuvent être utilisées pour favoriser l'utilisation d'un nœud plus
+puissant en fonction de la périodes de la journée ou du nombre de CPU.
+
+Il faut cependant garder à l'esprit que la bascule d'une ressource PostgreSQL n'est
+pas transparente et que la [simplicité][KISS] doit rester de mise.
+
+:::
+
+
+-----
+
+# PAF
+
+Configuration et Mécanique de PAF
+
+-----
+
+## Historique PAF
+
+* agent officiel `pgsql` fastidieux et vieillissant
+* premier agent stateless `pgsql-resource-agent`
+* PAF est la seconde génération en mode stateful
+* développé en bash, puis porté en perl
+
+::: notes
+
+Il existe déjà un agent `pgsql` distribué par le projet `resource-agents`.
+Cependant, cet agent accumule plusieurs défauts:
+
+* très fastidieux à mettre en œuvre
+* plusieurs objectifs: supporte les architectures _shared disk_ ou _shared nothing_
+* difficile à maintenir: code complexe, en bash
+* procédures lourdes: pas de switchover, procédures lourdes, fichier de lock, etc
+* configuration complexe: 31 paramètres disponibles
+* détails d'implémentation visibles dans le paramétrage
+* ne supporte pas le `demote` officieusement
+
+Pour les besoins d'un projet où cet agent était peu adapté à l'environnement,
+un premier agent stateless nommé `pgsqlsr` a été développé. C'est le projet
+`pgsql-resource-agent`, toujours disponible aujourd'hui mais plus maintenu. Ce
+projet avait l'avantage d'être très simple. Cependant, il imposait des limites
+importantes: un seul secondaire possible, un seul failover automatique
+autorisé, pas de switchover.
+
+Suite à cette expérience, les auteurs ont créés le projet PAF, un nouvel agent
+_multi-state_ exploitant au maximum les fonctionnalités de Pacemaker. Il a d'abord
+été développé en bash, puis porté en perl, langage plus bas niveau, plus
+lisible, plus efficace, plus fonctionnel.
+
+:::
+
+-----
+
+## Limitations
+
+* version de PostgreSQL supportée 9.3+
+* le demote de l'instance primaire nécessite un arrêt
+* trop strict sur l'arrêt brutal d'une instance
+* pas de reconstruction automatique de l'ancien primaire après failover
+* pas de gestion des slots de réplication
+
+::: notes
+
+Une incohérence entre l'état de l'instance et le controldata provoque une
+erreur fatale ! Ne __jamais__ utiliser `pg_ctl -m immediate stop` !
+
+Limitations levées:
+
+* ne gère pas plusieurs instances PostgreSQL sur un seul nœud. Corrigé dans le commit 1a7d375.
+* n'exclut pas une instance secondaire quel que soit son retard. Ajout du parametre maxlag dans le commit a3bbfa3.
+
+Fonctionnalités manquantes dans PostgreSQL pour améliorer la situation:
+
+* valider sur l'esclave ce qu'il a reçu du maître (cas du switchover)
+* demote «à chaud»
+
+:::
+
+-----
+
+## Installation PAF
+
+* disponible directement depuis les dépôts PGDG RPM ou DEB
+* paquets disponibles depuis github
+* possibilité de l'installer à la main
+
+::: notes
+
+PAF peut être installé manuellement ou via les paquets mis à disposition sur
+les dépôts communautaires PGDG ou encore ceux de Debian.
+
+Les paquets sont aussi mis à disposition depuis le dépôt github du projet:
+
+
+:::
+
+-----
+
+### TP: installation de PAF
+
+::: notes
+
+1. installer le dépôt PGDG pour CentOS 7 sur tous les nœuds
+2. installer PostgreSQL 12 sur sur tous les nœuds
+3. chercher puis installer le paquet de PAF sur tous les nœuds
+
+:::
+
+-----
+
+### Correction: installation de PAF
+
+::: notes
+
+1. installer le dépôt PGDG pour CentOS 7 sur tous les nœuds
+
+~~~console
+# yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm
+~~~
+
+2. installer PostgreSQL 12 sur sur tous les nœuds
+
+~~~console
+# yum install -y postgresql12 postgresql12-contrib postgresql12-server
+~~~
+
+3. chercher puis installer le paquet de PAF sur tous les nœuds
+
+~~~console
+# yum search paf
+Loaded plugins: fastestmirror
+Loading mirror speeds from cached hostfile
+ * base: centos.mirrors.proxad.net
+ * extras: centos.mirror.fr.planethoster.net
+ * updates: centos.crazyfrogs.org
+=============================== N/S matched: paf ===============================
+resource-agents-paf.noarch : PostgreSQL resource agent for Pacemaker
+
+ Name and summary matches only, use "search all" for everything.
+
+# yum install -y resource-agents-paf
+~~~
+
+:::
+
+-----
+
+## Pré-requis de PAF
+
+* supporte PostgreSQL à partir de la version 9.3 et supérieure
+* _hot standby_ actif: doit pouvoir se connecter aux secondaires
+* réplication streaming active entre les nœuds
+ * nécessite:
+ * `application_name` égal au nom du nœud
+ * `recovery_target_timeline = 'latest'`
+ * configurée dans :
+ * pg11 et avant : modèle de fichier de configuration `recovery.conf.pcmk`
+ * pg12 et après : fichier de configuration de PostgreSQL
+* le cluster PostgreSQL doit être prêt avant le premier démarrage
+* PostgreSQL doit être désactivé au démarrage du serveur
+* empêcher le _wal receiver_ de se connecter sur sa propre instance
+ * eg. ajout d'une règle `reject` dans `pg_hba.conf`
+
+::: notes
+
+L'agent PAF a peu de pré-requis.
+
+Il supporte toutes les version de PostgreSQL supérieure ou égale à la version
+9.3.
+
+Le `recovery.conf` a disparu avec la version 12 de PostgreSQL, les paramètres
+qu'il contenait sont désormais renseignés dans le fichier de configuration de
+l'instance.
+
+Le contrôleur du cluster à besoin de connaître le statut de chaque instance:
+primaire ou secondaire. Ainsi, l'action `monitor` est exécutée à intervalle
+régulier autant sur le primaire que sur les secondaires. Il est donc essentiel
+que le paramètre `hot standby` soit activé sur toutes les instances, même sur
+un primaire qui démarre toujours en secondaire d'abord ou qui peut être
+repositionné en secondaire sur décision du cluster ou sur commande.
+
+Au tout premier démarrage du cluster, PAF recherche parmi les instances
+configurées quel est l'instance principale. Il est donc essentiel d'avoir créé
+le cluster PostgreSQL avant la création de la ressource dans Pacemaker et
+que ce dernier soit fonctionnel dès son démarrage.
+
+Afin de permettre à PAF de faire le lien entre des connexions de réplication
+et le nom des nœuds du cluster, il faut donner le nom du nœud où se trouve
+l'instance dans la chaine de connexion (`primary_conninfo`) en utilisant le
+paramètre `application_name`.
+
+Lors de la création de la ressource, Pacemaker s'attend à la trouver éteinte.
+Il n'est pas vital que les instances soient éteintes, mais cela reste
+préférable afin d'éviter une légère perte de temps et des erreurs inutiles
+dans les log et les événements du cluster.
+
+Étant donné que Pacemaker contrôle entièrement le cluster PostgreSQL, ce
+dernier doit être désactivé au démarrage du serveur.
+
+Il est recommandé d'empêcher activement chaque instance de pouvoir se
+connecter en réplication avec elle même. La bascule étant automatique, un
+ancien primaire rétrogradé en secondaire pourrait se connecter à lui même si
+la mécanique d'aiguillage des connexions vers le nouveau primaire n'a pas
+encore convergé.
+
+La _timeline_ à l'intérieur des journaux de transaction est mise à jour par le
+serveur primaire suite à une promotion de l'instance. Pour que les instances
+secondaires se raccrochent à la primaire, il faut leur indiquer d'utiliser la
+dernière _timeline_ des journaux de transactions. C'est le rôle du
+paramètre `recovery_target_timeline` que l'on doit positionner à `latest`.
+
+:::
+
+-----
+
+### TP: création du cluster PostgreSQL
+
+::: notes
+
+Ce TP a pour but de créer les instances PostgreSQL. Il ne comporte pas de
+question, seulement des étapes à suivre.
+
+La configuration de PostgreSQL réalisée ci-dessous est une version simple et
+rapide. Elle convient au cadre de ce TP dont le sujet principal est Pacemaker
+et PAF, mais ne convient pas pour une utilisation en production.
+
+Dans ce cluster, l'adresse IP virtuelle `10.20.30.5` est associée au
+serveur hébergeant l'instance principale.
+
+Créer l'instance primaire sur le nœuds `hanode1` :
+
+~~~console
+# /usr/pgsql-12/bin/postgresql-12-setup initdb
+Initializing database ... OK
+~~~
+
+Configuration de l'instance:
+
+~~~console
+# su - postgres
+
+$ cat <> ~postgres/12/data/postgresql.conf
+listen_addresses = '*'
+wal_keep_segments = 32
+hba_file = '/var/lib/pgsql/12/pg_hba.conf'
+include = '../standby.conf'
+EOF
+
+$ cat < ~postgres/12/standby.conf
+primary_conninfo = 'host=10.20.30.5 application_name=$(hostname -s)'
+EOF
+~~~
+
+NB: depuis postgres 10, la mise en place de la réplication a été facilitée par
+de nouvelles valeurs par défaut pour `wal_level`, `hot_standby`, `max_wal_sender`,
+et `max_replication_slots`
+
+NB: avant la version 12, ces paramètres étaient à placer dans un modèle de
+configuration (eg. `recovery.conf.pcmk`) nécessaire à PAF.
+
+NB: avant la version 12, il est nécessaire de positionner
+`recovery_target_timeline = 'latest'`
+
+Notez que chaque fichier est différent sur chaque nœud grâce à l'utilisation du
+hostname local pour l'attribut `application_name`. Ce point fait parti de
+pré-requis, est essentiel et doit toujours être vérifié.
+
+Enfin, nous empêchons chaque instance de pouvoir entrer en réplication avec
+elle même dans le fichier `pg_hba.conf`. La dernière règle autorise toute autre
+connexion de réplication entrante:
+
+~~~console
+$ rm ~postgres/12/data/pg_hba.conf
+$ cat < ~postgres/12/pg_hba.conf
+local all all trust
+host all all 0.0.0.0/0 trust
+host all all ::/0 trust
+
+# forbid self-replication from vIP
+host replication postgres 10.20.30.5/32 reject
+# forbid self-replication its own IP
+host replication all $(hostname -s) reject
+local replication all reject
+host replication all 127.0.0.0/8 reject
+host replication all ::1/128 reject
+
+# allow any standby connection
+host replication postgres 0.0.0.0/0 trust
+EOF
+
+$ exit
+~~~
+
+NB: les fichiers de configuration propres à chaque instance sont positionnés
+hors du `PGDATA`. Ils sont ainsi conservés en cas de reconstruction de
+l'instance, ce qui évite des étapes supplémentaires pour les adapter
+systématiquement lors de cette procédure.
+
+Suite à cette configuration, nous pouvons démarrer l'instance principale et y
+associer l'adresse IP virtuelle choisie pour le primaire:
+
+~~~console
+# systemctl start postgresql-12
+# ip addr add 10.20.30.5/24 dev eth0
+~~~
+
+Cloner l'instance sur les serveurs secondaires `hanode2` et `hanode3`:
+
+~~~console
+# su - postgres
+$ /usr/pgsql-12/bin/pg_basebackup -h 10.20.30.5 -D ~postgres/12/data/ -P
+~~~
+
+Corriger le paramètre `primary_conninfo` sur chaque nœud:
+
+~~~console
+$ cat < ~postgres/12/standby.conf
+primary_conninfo = 'host=10.20.30.5 application_name=$(hostname -s)'
+EOF
+~~~
+
+Adapter les règles de rejet de la réplication du nœud avec lui même dans `pg_hba.conf`:
+
+~~~console
+$ cat < ~postgres/12/pg_hba.conf
+local all all trust
+host all all 0.0.0.0/0 trust
+host all all ::/0 trust
+
+# forbid self-replication from vIP
+host replication postgres 10.20.30.5/32 reject
+# forbid self-replication its own IP
+host replication all $(hostname -s) reject
+local replication all reject
+host replication all 127.0.0.0/8 reject
+host replication all ::1/128 reject
+
+# allow any standby connection
+host replication postgres 0.0.0.0/0 trust
+EOF
+~~~
+
+Démarrer les instances secondaires:
+
+~~~console
+$ touch ~postgres/12/data/standby.signal
+$ exit
+# systemctl start postgresql-12
+~~~
+
+NB: avant la version 12 de PostgreSQL, il faut copier le modèle template de
+`recovery.conf` (eg. `recovery.conf.pcmk`) dans le `PGDATA` au lieu de créer
+le fichier `standby.signal`.
+
+Vérifier le statut de la réplication depuis le serveur primaire :
+
+~~~console
+postgres=# TABLE pg_stat_replication;
+~~~
+
+Enfin, éteindre tous les services PostgreSQL et les désactiver, comme indiqué
+dans les pré-requis. Commencer par le primaire sur `hanode1`.
+
+~~~console
+# systemctl disable --now postgresql-12
+~~~
+
+Supprimer également l'adresse ip virtuelle ajoutée précédemment, celle-ci est
+également contrôlée par Pacemaker par la suite :
+
+~~~console
+# ip addr del 10.20.30.5/24 dev eth0
+~~~
+
+:::
+
+-----
+
+## Configuration de PAF
+
+* Obligatoire: `PGDATA`
+* Paramétrage avant la version 12 : `recovery_template`
+* nécessite l'activation des opération `notify`
+* Rappel : préciser tous les timeout des opérations
+* Rappel : configurer deux opérations `monitor`
+
+::: notes
+
+La configuration de la ressource PostgreSQL est faite avec les paramètres :
+
+* `bindir` : localisation des binaires de PostgreSQL (défaut: `/usr/bin`)
+* `pgdata` : localisation du PGDATA de l'instance (défaut: `/var/lib/pgsql/data`)
+* `datadir` : chemin du répertoire data_directory si il est différent de `PGDATA`
+* `pghost` : le répertoire de socket ou l'adresse IP pour se connecter à l'instance
+ locale (défaut: `/tmp` ou `/var/run/postgresql` pour Debian et dérivés)
+* `pgport` : le port de l'instance locale (défaut: `5432`)
+* `recovery_template` : un template local pour le fichier `PGDATA/recovery.conf`
+(défaut: `$PGDATA/recovery.conf.pcmk`)
+ * avant PG12 : Ce fichier __doit__ exister sur tous les nœuds ;
+ * à partir de PG12 : Ce fichier ne doit exister sur aucun nœuds.
+* `start_opts` : Argument supplémentaire à donner au processus PostgreSQL au démarrage
+ de PostgreSQL (vide pas défaut).
+* `system_user` : l'utilisateur système du propriétaire de l'instance (défaut: `postgres`)
+* `maxlag` : lag maximal autorisé pour une standby avant d'y placer un score négatif.
+ La différence est calculée entre la position actuelle dans le journal de transaction
+ sur le master et la postion écrite sur la standby (défaut: `0`, désactive la
+ fonction)
+
+Concernant la configuration des opérations, il est important de rappeler que
+les timeout des opérations sont pas défaut de 20 secondes. Voir à ce propos le
+chapitre [Création d'une ressource]. Les timeouts précisés dans la description
+de l'agent `pgsqlms` ne sont __que__ des valeurs recommandées. Il __faut__
+préciser ce timeout en s'inspirant des valeurs conseillées pour __chaque__
+opération.
+
+Comme expliqué dans le chapitre [Ressources _Multi-State_], il faut
+configurer deux opérations `monitor` distinctes: une pour le rôle `Slave`,
+l'autre pour le rôle `Master`. Rappelez-vous que ces opérations doivent avoir
+des périodes d'exécution différentes.
+
+Concernant la ressource multi-state prenant en charge les clones, il est
+essentiel d'activer les opérations `notify` qui sont désactivées par défaut.
+Effectivement, l'agent `pgsqlms` utilise intensément cette opération pour
+détecter les cas de _switchover_, de _recovery_, gérer l'élection du
+secondaire à promouvoir, etc.
+
+Les différentes opérations pour passer d'un état à l'autre sont deviennent
+alors les suivantes:
+
+
+
+:::
+
+-----
+
+### TP: création ressource PAF
+
+::: notes
+
+Effectuer les modifications dans un fichier `pgsqld.xml` avant de les appliquer
+au cluster.
+
+1. créer une ressource `pgsqld` en précisant:
+
+* les paramètres `bindir` et `pgdata`
+* les timeout de toutes les actions. Utiliser les timeout recommandé par
+ l'agent
+* surveiller le rôle `Master` toutes les 15 secondes
+* surveiller le rôle `Slave` toutes les 16 secondes
+
+2. créer la ressource `pgsqld-clone` responsable des clones de `pgsqld`
+3. créer la ressource `pgsql-master-ip` gérant l'adresse `10.20.30.5`
+4. ajouter une colocation obligatoire entre l'instance primaire de `pgsqld-clone`
+ et `pgsql-master-ip`
+5. ajouter une contrainte asymétrique pour promouvoir `pgsqld-clone` avant de
+ démarrer `pgsql-master-ip`
+6. ajouter une contrainte asymétrique pour rétrograder `pgsqld-clone` avant
+ d'arrêter `pgsql-master-ip`
+7. vérifier la configuration créée puis appliquer la au cluster
+8. observer le score `master-pgsqld` des clones `pgsqld`
+
+:::
+
+-----
+
+### Correction: ressource PAF
+
+::: notes
+
+Effectuer les modifications dans un fichier `pgsqld.xml` avant de les appliquer
+au cluster.
+
+~~~console
+# pcs cluster cib pgsqld.xml
+~~~
+
+1. créer une ressource `pgsqld`
+
+~~~console
+# pcs -f pgsqld.xml resource create pgsqld ocf:heartbeat:pgsqlms \
+ bindir=/usr/pgsql-12/bin pgdata=/var/lib/pgsql/12/data \
+ op start timeout=60s \
+ op stop timeout=60s \
+ op promote timeout=30s \
+ op demote timeout=120s \
+ op monitor interval=15s timeout=10s role="Master" \
+ op monitor interval=16s timeout=10s role="Slave" \
+ op notify timeout=60s
+~~~
+
+2. créer la ressource `pgsqld-clone` responsable des clones de `pgsqld`
+
+~~~console
+# pcs -f pgsqld.xml resource master pgsqld-clone pgsqld notify=true
+~~~
+
+Nous ne précisons ici la seule option `notify` qui est __essentielle__ à PAF
+et qui est par défaut à `false`. Elle permet d'activer les action `notify`
+avant et après chaque action sur la ressource. Nous laissons les autres
+options à leur valeur par défaut.
+
+3. créer la ressource `pgsql-master-ip` gérant l'adresse `10.20.30.5`
+
+~~~console
+# pcs -f pgsqld.xml resource create pgsql-master-ip ocf:heartbeat:IPaddr2 \
+ ip=10.20.30.5 cidr_netmask=24 \
+ op monitor interval=10s
+~~~
+
+4. ajouter une colocation obligatoire entre l'instance primaire de `pgsqld-clone`
+ et `pgsql-master-ip`
+
+~~~console
+# pcs -f pgsqld.xml constraint \
+ colocation add pgsql-master-ip with master pgsqld-clone INFINITY
+~~~
+
+5. ajouter une contrainte asymétrique pour promouvoir `pgsqld-clone` avant de
+ démarrer `pgsql-master-ip`
+
+~~~console
+# pcs -f pgsqld.xml constraint order promote pgsqld-clone \
+ then start pgsql-master-ip symmetrical=false kind=Mandatory
+~~~
+
+6. ajouter une contrainte asymétrique pour rétrograder `pgsqld-clone`
+ avant d'arrêter `pgsql-master-ip`
+
+~~~console
+# pcs -f pgsqld.xml constraint order demote pgsqld-clone \
+ then stop pgsql-master-ip symmetrical=false kind=Mandatory
+~~~
+
+7. vérifier la configuration créée puis appliquer la au cluster
+
+~~~console
+# pcs cluster verify -V pgsqld.xml
+
+# crm_simulate -S -x pgsqld.xml
+
+# pcs cluster cib-push pgsqld.xml
+~~~
+
+:::
+
+-----
+
+## Master scores de PAF
+
+* mécanique des master scores de PAF
+* `1001` pour le primaire
+* `1000 - 10 x n` pour les secondaires
+* score négatif en cas de décrochage ou retard
+* cas du premier démarrage
+
+::: notes
+
+PAF positionne des _master scores_ permanents, qui sont conservés entre les
+redémarrage du cluster. Le dernier emplacement du primaire est donc toujours
+maintenu au sein du cluster. Il n'est pas recommandé de manipuler soit même
+ces scores, nous étudions plus loin les commandes d'administration permettant
+d'agir sur l'emplacement du primaire.
+
+Lors du démarrage d'une instance arrêtée alors qu'elle était primaire, l'agent
+positionnera son master score à `1` si aucun autre master score n'est connu au
+sein du cluster. Les master scores n'étant jamais supprimés par le cluster,
+cette mécanique est principalement utile lors du tout premier démarrage.
+
+Une fois la promotion effectuée, le score positionné par l'agent pour assurer
+son statu d'instance primaire est de `1001`.
+
+Le score des instances secondaires est mis à jour lors de l'opération `monitor`
+sur le primaire. Il peut donc être nécessaire d'attendre un cycle de cette
+opération avant que les scores ne soient mis à jour, par exemple, suite à une
+bascule. Voici les scores attribués:
+
+* positif: le statut de réplication de l'instance est `stream`
+* `-1`: statut de réplication est `startup` ou `backup`
+* `-1000`: l'instance n'est pas connectée au primaire
+* négatif: l'instance a un lag supérieur au paramètre `max_lag` positionné
+sur la ressource `pgsqlms`
+
+Les scores positifs distribués aux secondaires en réplication sont dégressifs
+par pas de `10` à partir de `1000`. L'ordre dépend de deux critères: le lag
+avec le primaire et le nom de l'instance tel que positionné dans
+`application_name`.
+
+Suite au précédent TP, vous devriez observer les scores suivants:
+
+~~~console
+# crm_simulate -sL|grep promotion
+pgsqld:0 promotion score on hanode1: 1003
+pgsqld:1 promotion score on hanode2: 1000
+pgsqld:2 promotion score on hanode3: 990
+~~~
+
+Tout d'abord, nous observons que le cluster a choisi de démarrer trois clones
+en respect de la valeur par défaut du paramètre `clone-max`, positionnée au
+nombre de nœuds existants. Ces ressources sont suffixé d'un identifiant:
+`pgsqld:0`, `pgsqld:1` et `pgsqld:2`.
+
+Concernant le placement des clones, le cluster actuellement configuré doit
+présenter des scores similaires à ceux-ci:
+
+~~~console
+# crm_simulate -sL|grep 'native_color: pgsqld'
+native_color: pgsqld:0 allocation score on hanode1: 1002
+native_color: pgsqld:0 allocation score on hanode2: 0
+native_color: pgsqld:0 allocation score on hanode3: 0
+native_color: pgsqld:1 allocation score on hanode1: -INFINITY
+native_color: pgsqld:1 allocation score on hanode2: 1001
+native_color: pgsqld:1 allocation score on hanode3: 0
+native_color: pgsqld:2 allocation score on hanode1: -INFINITY
+native_color: pgsqld:2 allocation score on hanode2: -INFINITY
+native_color: pgsqld:2 allocation score on hanode3: 991
+~~~
+
+Les scores `1002`, `1001` et `991` correspondent à la somme des _master scores_
+avec le _stickiness_ de `1` associé à la ressource.
+
+Voici pourquoi et comment sont distribués les scores `-INFINITY`:
+
+1. le premier clone `pgsqld:0` pouvait démarrer n'importe où.
+2. une fois `pgsqld:0` démarré sur `hanode1`, les clones ne pouvant coexister sur
+ le même nœud (`clone-node-max=1`), `pgsqld:1` a un score `-INFINITY` sur
+ `hanode1`, mais peu démarrer sur n'importe lequel des deux autres nœuds
+3. `pgsqld:2` a un score de `-INFINITY` sur `hanode1` et `hanode2` à cause de la
+ présence des deux autres clones. Il ne peut démarrer que sur `hanode3`.
+
+NB: il se peut que vos clones soient répartis différemment.
+
+:::
+
+-----
+
+### TP: étude du premier démarrage
+
+::: notes
+
+Le log de `LRMd` étant configuré en mode debug, les messages de debug de PAF
+son visibles dans les log.
+
+1. identifier l'opération `start` dans les log de Pacemaker __sur le primaire__
+2. identifier les messages de `pgsqlms` concernant son statut avant et après démarrage
+3. identifier la décision de l'agent de positionner son master score
+4. identifier sur le DC la décision de créer une nouvelle transition pour
+ promouvoir l'instance primaire
+5. identifier l'opération de promotion sur le primaire
+6. identifier sur le primaire la distributions des scores
+
+:::
+
+-----
+
+### Correction: Étude du premier démarrage
+
+::: notes
+
+Le log de `LRMd` étant configuré en mode debug, les messages de debug de PAF
+son visibles dans les log.
+
+1. identifier l'opération `start` dans les log de Pacemaker __sur le primaire__
+
+~~~
+lrmd: info: executing - rsc:pgsqld action:start call_id:27
+~~~
+
+2. identifier les messages de `pgsqlms` concernant son statut avant et après démarrage
+
+~~~
+pgsqlms(pgsqld) DEBUG: _controldata: instance "pgsqld" state is "shut down"
+~~~
+
+Au début de l'opération `start`, `pgsqlms` vérifie toujours le statut de
+l'instance en effectuant les mêmes contrôles que l'opération `monitor`. Il
+détecte bien ici que l'instance est arrêtée en tant que primaire.
+
+Pour comparaison, une instance secondaire est signalée avec le message suivant:
+
+~~~
+pgsqlms(pgsqld) DEBUG: instance "pgsqld" state is "shut down in recovery"
+~~~
+
+Une fois l'opération confirmée, nous constatons bien que le l'instance est
+démarrée en tant que standby.
+
+~~~
+pgsqlms(pgsqld) DEBUG: _confirm_role: instance pgsqld is a secondary
+pgsqlms(pgsqld) INFO: Instance "pgsqld" started
+~~~
+
+
+3. identifier la décision de l'agent de positionner son master score
+
+~~~
+pgsqlms(pgsqld) INFO: No master score around. Set mine to 1
+~~~
+
+Vous remarquerez que ce message n'apparaît sur les autres instances.'
+
+4. identifier sur le DC la décision de créer une nouvelle transition pour
+ promouvoir l'instance primaire
+
+~~~
+pengine: debug: pgsqld:1 master score: 1
+pengine: info: Promoting pgsqld:1 (Slave hanode1)
+pengine: debug: pgsqld:0 master score: -1
+pengine: debug: pgsqld:2 master score: -1
+pengine: info: pgsqld-clone: Promoted 1 instances of a possible 1 to master
+pengine: debug: Assigning hanode1 to pgsql-master-ip
+[...]
+pengine: info: Leave pgsqld:0 (Slave hanode2 )
+pengine: notice: * Promote pgsqld:1 (Slave -> Master hanode1)
+pengine: info: Leave pgsqld:2 (Slave hanode3 )
+pengine: notice: * Start pgsql-master-ip (hanode1 )
+~~~
+
+Cette transition décide de promouvoir l'instance sur `hanode1` et d'y
+démarrer l'adresse IP associée grâce à la colocation créée.
+
+5. identifier l'opération de promotion sur le primaire
+
+~~~
+crmd: info: Performing op=pgsqld_promote_0
+lrmd: info: executing - rsc:pgsqld action:promote
+[...]
+pgsqlms(pgsqld)[29050]: Mar 20 21:52:40 INFO: Promote complete
+lrmd: info: finished - rsc:pgsqld action:promote exit-code:0
+crmd: notice: Result of promote operation for pgsqld on hanode1: 0 (ok)
+~~~
+
+6. identifier sur le primaire la distributions des scores
+
+Une fois la promotion réalisée et avant de la confirmer au cluster, l'agent
+vérifie le statut de l'instance de la même manière que l'opération `monitor`.
+L'adresse IP n'étant pas encore associée à ce moment là, aucun secondaire n'est
+alors connecté. Vous devriez donc observer les messages suivants:
+
+~~~
+pgsqlms(pgsqld) WARNING: No secondary connected to the master
+pgsqlms(pgsqld) WARNING: "hanode3" is not connected to the primary
+pgsqlms(pgsqld) WARNING: "hanode2" is not connected to the primary
+~~~
+
+Au prochain appel à l'opération `monitor`, vous devriez ensuite observer:
+
+~~~
+pgsqlms(pgsqld) INFO: Update score of "hanode2" from -1000 to 1000 because of a change in the replication lag (0).
+pgsqlms(pgsqld) INFO: Update score of "hanode3" from -1000 to 990 because of a change in the replication lag (0).
+~~~
+
+:::
+
+-----
+
+# Administration du cluster
+
+-----
+
+## Démarrer/arrêter le cluster
+
+* pas de mécanique d'arrêt contrôlé et simultané de tous les nœuds
+* désactiver les ressources avant d'éteindre le cluster
+* au cas par cas ou avec l'option `stop-all-resources`
+* utiliser l'attribut de nœuds `standby` pour un nœud isolé
+
+::: notes
+
+Pacemaker n'a pas de mécanique prévue pour interrompre tous les nœuds du
+cluster de façon contrôlée. Ainsi, si les nœuds sont éteints les uns après
+les autres, quele qu'en soit la raison, le cluster peut avoir le temps de
+réagir et planifier des opérations qui pourront être exécutées ou non.
+
+Même avec un outil comme `pcs` qui exécute les commandes d'arrêts sur tous
+les nœuds en même temps, il y a toujours un risque de race condition.
+
+À ce propos, voir ce mail et la discussion autour:
+
+
+
+Il existe deux solutions pour éteindre le cluster, arrêter les ressources ou
+positionner le paramètre de cluster `stop-all-resources` à `true`.
+
+Si l'arrêt ne concerne qu'un seul serveur (eg. mise à jour du noyau,
+évolution matériel, ...), il est possible de le positionner en
+« veille » grâce à l'attribut de nœud `standby`. Lorsque cet attribut est
+activé sur un nœud, Pacemaker bascule toutes les ressources qu'il héberge
+ailleurs dans le cluster et n'en démarrera plus dessus.
+
+:::
+
+-----
+
+### TP: arrêt du cluster
+
+::: notes
+
+1. placer `hanode3` en mode standby
+2. observer les contraintes pour `pgsqld-clone`
+3. retirer le mode standby de `hanode3`
+4. désactiver toutes les ressources
+5. éteindre le cluster
+6. démarrer le cluster
+7. réactiver les ressources.
+
+:::
+
+-----
+
+### Correction: arrêt du cluster
+
+::: notes
+
+1. placer `hanode3` en mode standby
+
+~~~console
+# pcs node standby hanode3 --wait
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 ]
+ Stopped: [ hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+Toutes les ressources de `hanode3` ont bien été interrompues.
+
+NOTE: `pcs node standby ` à remplacé `pcs cluster standby` dans la
+version 0.10.1 de pcs.
+
+
+2. observer les contraintes pour `pgsqld-clone`
+
+~~~console
+# pcs constraint location show resource pgsqld-clone
+Location Constraints:
+~~~
+
+Il n'y a aucune contrainte, le cluster refuse simplement de démarrer une
+ressource sur `hanode3`.
+
+3. retirer le mode standby de `hanode3`
+
+~~~console
+# pcs node unstandby hanode3 --wait
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+4. désactiver toutes les ressources
+
+Deux solutions. La première consiste à positionner `stop-all-resources=true`:
+
+~~~console
+# pcs property set stop-all-resources=true
+
+# [...] après quelques secondes
+
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Stopped: [ hanode1 hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Stopped
+~~~
+
+L'intérêt de se paramètre est que le cluster va interrompre toutes les
+ressources en une seule transition:
+
+~~~
+pengine: debug: unpack_config: Stop all active resources: true
+pengine: debug: native_color: Forcing fence_vm_hanode1 to stop
+pengine: debug: native_color: Forcing fence_vm_hanode2 to stop
+pengine: debug: native_color: Forcing fence_vm_hanode3 to stop
+pengine: debug: native_color: Forcing pgsqld:1 to stop
+pengine: debug: native_color: Forcing pgsqld:0 to stop
+pengine: debug: native_color: Forcing pgsqld:2 to stop
+pengine: notice: * Stop fence_vm_hanode1 ( hanode2 )
+pengine: notice: * Stop fence_vm_hanode2 ( hanode1 )
+pengine: notice: * Stop fence_vm_hanode3 ( hanode1 )
+pengine: notice: * Stop pgsqld:0 ( Slave hanode2 )
+pengine: notice: * Stop pgsqld:1 ( Master hanode1 )
+pengine: notice: * Stop pgsqld:2 ( Slave hanode3 )
+pengine: notice: * Stop pgsql-master-ip ( hanode1 )
+~~~
+
+Son désavantage est que le cluster réagit après que le paramètre ait été
+positionné. L'outil `pcs` ne peut donc pas attendre la fin de la transition
+pour rendre la main, ce qui est gênant dans le cadre d'un script par exemple.
+
+La seconde solution consiste à arrêter chacune des ressources, une à une.
+Dans ce cas, nous pouvons demander à `pcs` d'attendre la fin de l'opération,
+mais il faut potentiellement exécuter plusieurs commandes donc.
+
+~~~console
+# pcs resource disable pgsqld-clone --wait
+~~~
+
+5. éteindre le cluster
+
+~~~console
+# pcs cluster stop --all
+~~~
+
+6. démarrer le cluster
+
+~~~console
+# pcs cluster start --all
+~~~
+
+7. réactiver les ressources.
+
+Attendre que le cluster soit formé et qu'un DC soit élu.
+
+~~~console
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Stopped: [ hanode1 hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Stopped
+# pcs property set stop-all-resources=false
+
+[...] après quelques secondes
+
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+:::
+
+-----
+
+## Maintenances du cluster
+
+* `maintenance-mode`
+ * concerne toutes les ressources
+ * désactive toutes les opérations
+ * arrête les opérations `monitor`
+* `is-managed`
+ * ressource par ressource
+ * ne désactive pas les opérations `monitor`
+ * ne réagit plus aux changements de statut
+* commandes `cleanup` ou `refresh` pour rafraîchir une ressource
+
+::: notes
+
+L'attribut de ressource `is-managed` permet de désactiver les réactions du
+cluster pour la ressource concernée. Une fois cet attribut positionné à
+`false`, le cluster n'exécute plus aucune nouvelle action de sa propre
+initiative. Cependant, les opérations récurrentes de `monitor` sont maintenues.
+Un statut différent de celui attendu n'est simplement pas considéré comme une
+erreur.
+
+Le paramètre `maintenance-mode` quand à lui permet de placer l'ensemble du
+cluster en mode maintenance lorsqu'il est positionné à `true`. Ce paramètre
+de cluster concerne __toutes__ les ressources.
+
+Une fois le mode maintenance activé, comme avec l'attribut `is-managed`,
+Pacemaker n'exécute plus aucune opération de sa propre initiative, mais il
+désactive __aussi__ toutes les opérations récurrentes de `monitor`.
+
+Quelque soit la méthode utilisée pour désactiver temporairement les réactions
+du cluster, une fois que ce dernier reprend le contrôle, il compare le statut
+des ressources avec celui qu'elles avaient auparavant. Ainsi, si une ressource
+a été arrêtée ou déplacée entre temps, il peut déclencher des actions
+correctives ! Avant de quitter l'un ou l'autre des modes, veillez à simuler la
+réaction du cluster à l'aide de `crm_simulare`.
+
+Lorsque `maintenance-mode` est activé, il peut être utile de demander au
+cluster de rafraîchir le statut des ressources. Deux commandes existent:
+`crm_ressource --cleanup` ou `crm_ressource --refresh` (et leurs équivalents
+avec `pcs`).
+
+La première ne travaille que sur les ressources ayant eu une erreur. Elle
+nettoie l'historique des erreurs, les `failcount`, puis exécute une
+seule opération `monitor` pour recalculer le statut de la ressource. Elle n'a
+aucun effet sur les ressources n'ayant aucune erreur.
+
+La seconde commande effectue les mêmes opérations, travaille aussi sur les
+ressources saines et nettoie tout l'historique en plus des erreurs.
+
+:::
+
+-----
+
+### TP: maintenance
+
+::: notes
+
+1. désactiver `is-managed` pour la ressource `pgsqld-clone`
+2. arrêter manuellement PostgreSQL sur `hanode2`
+3. observer la réaction du cluster
+4. exporter la CIB courante dans le fichier `is-managed.xml` et y activer le
+ paramètre `is-managed` pour la ressource `pgsqld-clone`
+5. simuler la réaction du cluster en utilisant la CIB `is-managed.xml` en entrée
+6. appliquer la modification de `is-managed.xml` et observer la réaction du
+ cluster
+7. activer le mode maintenance sur l'ensemble du cluster
+8. arrêter manuellement PostgreSQL sur `hanode3`
+9. exécuter une commande `cleanup` pour `pgsqld` sur le seul nœud `hanode2`
+10. exécuter une commande `cleanup` pour `pgsqld` sur le seul nœud `hanode3`
+11. exécuter une commande `refresh` pour `pgsqld` sur le seul nœud `hanode3`
+12. simuler la sortie du mode maintenance puis appliquer la modification au
+ cluster
+
+:::
+
+-----
+
+### Correction: maintenance
+
+::: notes
+
+1. désactiver `is-managed` pour la ressource `pgsqld-clone`
+
+~~~console
+# pcs resource unmanage pgsqld-clone
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode1 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode2 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode3 (unmanaged)
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+2. arrêter manuellement PostgreSQL sur `hanode2`
+
+Notez que nous ne pouvons pas utiliser `systemctl`. Le service est
+désactivé et arrêté aux yeux de systemd.
+
+~~~console
+# sudo -iu postgres /usr/pgsql-12/bin/pg_ctl -D /var/lib/pgsql/12/data/ -m fast stop
+~~~
+
+3. observer la réaction du cluster
+
+Après quelques secondes, le cluster constate que `pgsqld` est arrêté sur
+`hanode2`, mais il ne réagit pas.
+
+~~~console
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode1 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode3 (unmanaged)
+ Stopped: [ hanode2 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+Les log sur le DC présentent bien la non réaction du `pengine`:
+
+~~~
+pengine: debug: pgsqld_monitor_16000 on hanode2 returned 'not running' (7) instead of the expected value: 'ok' (0)
+pengine: info: resource pgsqld:1 isn't managed
+[...]
+pengine: debug: custom_action: Action pgsqld:0_start_0 (unmanaged)
+pengine: debug: custom_action: Action pgsqld:0_demote_0 (unmanaged)
+pengine: debug: custom_action: Action pgsqld:0_stop_0 (unmanaged)
+pengine: debug: custom_action: Action pgsqld:0_promote_0 (unmanaged)
+pengine: debug: custom_action: Action pgsqld:1_start_0 (unmanaged)
+pengine: debug: custom_action: Action pgsqld:1_stop_0 (unmanaged)
+pengine: debug: custom_action: Action pgsqld:1_start_0 (unmanaged)
+pengine: info: LogActions: Leave fence_vm_hanode1 (Started hanode2)
+pengine: info: LogActions: Leave fence_vm_hanode2 (Started hanode1)
+pengine: info: LogActions: Leave fence_vm_hanode3 (Started hanode1)
+pengine: info: LogActions: Leave pgsqld:0 (Master unmanaged)
+pengine: info: LogActions: Leave pgsqld:1 (Slave unmanaged)
+pengine: info: LogActions: Leave pgsqld:2 (Stopped unmanaged)
+pengine: info: LogActions: Leave pgsql-master-ip (Started hanode1)
+~~~
+
+4. exporter la CIB courante dans le fichier `is-managed.xml` et y activer le
+paramètre `is-managed` pour la ressource `pgsqld-clone`
+
+~~~console
+# pcs cluster cib is-managed.xml
+# pcs -f is-managed.xml resource manage pgsqld-clone
+~~~
+
+5. simuler la réaction du cluster en utilisant la CIB `is-managed.xml` en entrée
+
+Le cluster décide de redémarrer l'instance sur `hanode2`.
+
+~~~console
+# crm_simulate -Sx is-managed.xml
+[...]
+Transition Summary:
+ * Recover pgsqld:2 ( Slave hanode2 )
+
+Executing cluster transition:
+ * Pseudo action: pgsqld-clone_pre_notify_stop_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_stop_0
+ * Pseudo action: pgsqld-clone_stop_0
+ * Resource action: pgsqld stop on hanode2
+ * Pseudo action: pgsqld-clone_stopped_0
+ * Pseudo action: pgsqld-clone_post_notify_stopped_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_stopped_0
+ * Pseudo action: pgsqld-clone_pre_notify_start_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_start_0
+ * Pseudo action: pgsqld-clone_start_0
+ * Resource action: pgsqld start on hanode2
+ * Pseudo action: pgsqld-clone_running_0
+ * Pseudo action: pgsqld-clone_post_notify_running_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_running_0
+ * Resource action: pgsqld monitor=16000 on hanode2
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+6. appliquer la modification de `is-managed.xml` et observer la réaction du cluster
+
+~~~console
+# pcs cluster cib-push is-managed.xml
+~~~
+
+Le cluster détecte __immédiatement__ un statut différent de celui attendu et
+lève une erreur:
+
+~~~console
+# pcs resource failcount show pgsqld
+Failcounts for resource 'pgsqld'
+ hanode2: 1
+~~~
+
+Dans les log du DC:
+
+~~~
+pengine: debug: pgsqld_monitor_16000 on hanode2 returned 'not running' (7) instead of the expected value: 'ok' (0)
+pengine: warning: Processing failed monitor of pgsqld:1 on hanode2: not running | rc=7
+pengine: info: Start recurring monitor (16s) for pgsqld:1 on hanode2
+pengine: info: Start recurring monitor (16s) for pgsqld:1 on hanode2
+pengine: info: Leave fence_vm_hanode1 (Started hanode2)
+pengine: info: Leave fence_vm_hanode2 (Started hanode1)
+pengine: info: Leave fence_vm_hanode3 (Started hanode1)
+pengine: info: Leave pgsqld:0 (Master hanode1 )
+pengine: notice: * Recover pgsqld:1 (Slave hanode2 )
+pengine: info: Leave pgsqld:2 (Slave hanode3 )
+pengine: info: Leave pgsql-master-ip (Started hanode1)
+~~~
+
+7. activer le mode maintenance sur l'ensemble du cluster
+
+Le cluster ne gère plus aucune les ressource.
+
+~~~console
+# pcs property set maintenance-mode=true
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld] (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode3 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode1 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode2 (unmanaged)
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1 (unmanaged)
+~~~
+
+8. arrêter manuellement PostgreSQL sur `hanode3`
+
+~~~console
+# sudo -iu postgres /usr/pgsql-12/bin/pg_ctl -D /var/lib/pgsql/12/data/ -m fast stop
+~~~
+
+Le cluster ne détecte pas le changement de statut de la ressource.
+
+9. exécuter une commande `cleanup` pour `pgsqld` sur le seul nœud `hanode2`
+
+~~~console
+# pcs resource cleanup pgsqld --node=hanode2
+Cleaned up pgsqld:0 on hanode2
+Cleaned up pgsqld:1 on hanode2
+Cleaned up pgsqld:2 on hanode2
+
+# pcs resource failcount show pgsqld
+No failcounts for resource 'pgsqld'
+
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld] (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode3 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode1 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode2 (unmanaged)
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1 (unmanaged)
+~~~
+
+Nous observons que l'historique des incidents de `pgsqld` sur `hanode2` a disparu.
+
+Le clone `pgsqld` est cependant toujours vu comme démarré sur `hanode3`.
+
+10. exécuter une commande `cleanup` pour `pgsqld` sur le seul nœud `hanode3`
+
+Rien ne change. La commande n'a pas d'effet sur les ressources n'ayant pas eu
+d'incident.
+
+~~~console
+# pcs resource cleanup pgsqld --node=hanode3
+Cleaned up pgsqld:0 on hanode3
+Cleaned up pgsqld:1 on hanode3
+Cleaned up pgsqld:2 on hanode3
+
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld] (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode3 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode1 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode2 (unmanaged)
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1 (unmanaged)
+~~~
+
+11. exécuter une commande `refresh` pour `pgsqld` sur le seul nœud `hanode3`
+
+Le cluster a détecté que la ressource était arrêtée et le consigne dans la
+CIB.
+
+~~~console
+# pcs resource refresh pgsqld --node=hanode3
+Cleaned up pgsqld:0 on hanode3
+Cleaned up pgsqld:1 on hanode3
+Cleaned up pgsqld:2 on hanode3
+Waiting for 3 replies from the CRMd... OK
+
+# pcs resource failcount show pgsqld
+No failcounts for resource 'pgsqld'
+
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld] (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode1 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode2 (unmanaged)
+ Stopped: [ hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1 (unmanaged)
+~~~
+
+12. simuler la sortie du mode maintenance puis appliquer la modification au
+cluster
+
+Le cluster prévoie de démarrer l'instance sur `hanode3`
+
+~~~console
+# pcs cluster cib maintenance-mode.xml
+# pcs -f maintenance-mode.xml property set maintenance-mode=false
+# crm_simulate -Sx maintenance-mode.xml
+[...]
+Transition Summary:
+ * Start pgsqld:2 ( hanode3 )
+
+Executing cluster transition:
+ * Resource action: fence_vm_hanode1 monitor=60000 on hanode2
+ * Resource action: fence_vm_hanode2 monitor=60000 on hanode1
+ * Resource action: fence_vm_hanode3 monitor=60000 on hanode1
+ * Pseudo action: pgsqld-clone_pre_notify_start_0
+ * Resource action: pgsql-master-ip monitor=10000 on hanode1
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_start_0
+ * Pseudo action: pgsqld-clone_start_0
+ * Resource action: pgsqld start on hanode3
+ * Pseudo action: pgsqld-clone_running_0
+ * Pseudo action: pgsqld-clone_post_notify_running_0
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_running_0
+ * Resource action: pgsqld monitor=15000 on hanode1
+ * Resource action: pgsqld monitor=16000 on hanode2
+ * Resource action: pgsqld monitor=16000 on hanode3
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+Après avoir appliqué la modification sur le cluster, ce dernier démarre
+effectivement la ressource, mais aucune erreur n'est levée. Le cluster
+s'aperçoit simplement qu'il peut déployer une instance de plus.
+
+~~~console
+# pcs cluster cib-push maintenance-mode.xml
+# pcs resource failcount show pgsqld
+No failcounts for resource 'pgsqld'
+~~~
+
+:::
+
+-----
+
+## Simuler des événements
+
+* la commande `crm_simulate` permet de simuler les réactions du cluster
+* elle peut aussi injecter des événements, eg.:
+ * crash d'un nœud
+ * injecter une opération et son code retour, avant transition
+ * décider du code retour d'une opération pour la prochaine transition
+* chaque appel exécute une seule transition
+* possibilité de chaîner les simulations en reprenant le résultat de la précédente
+* utile pour analyser les transitions passées
+
+::: notes
+
+Jusqu'à présent l'outil `crm_simulate` a été utilisé pour simuler les
+réactions du cluster en fonction d'une situation stable: une CIB de travail
+dans un fichier XML que nous manipulons (`crm_simulate -S -x FICHIER`) ou la
+CIB en cours d'utilisation par le cluster (`crm_simulate -S -L`).
+
+Il est aussi possible d'utiliser cet outil pour injecter des opérations et
+leur code retour grâce à l'argument `--op-inject` ou `-i`. Le format de
+l'argument est alors le suivant:
+`${resource}_${task}_${interval}@${node}=${rc}`, avec:
+
+* `${resource}`: le nom de la ressource
+* `${task}`: l'opération'
+* `${interval}`: l'intervalle de récurrence de la commande, en millisecondes
+* `${node}`: le nœud sur lequel l'opération est simulée
+* `${rc}`: le code retour.
+
+Le code retour doit être précisé de façon numérique. La liste des codes
+retours est disponible dans le chapitre [_Ressource Agent_ (_RA_)].
+
+Par exemple, la commande suivante injecte une opération `monitor` indiquant que
+la ressource `pgsqld` est arrêtée sur `hanode2`:
+
+~~~
+--op-inject=pgsqld_monitor_15000@hanode2=7
+~~~
+
+L'argument `--op-fail` ou `-F` permet de prédire le code retour d'une opération
+si elle est planifiée durant la simulation. Le format est identique à celui de
+`--op-inject`. Il est donc possible d'injecter une opération en entrée de la
+simulation avec `--op-inject` et de prédire le code retour d'une ou plusieurs
+des opérations planifiées par le cluster en réponse.
+
+D'autres événements sont supportés, tel que l'arrêt d'un nœud ou sa
+défaillance (respectivement `--node-down` et `--node-fail`), le changement de
+quorum (`--quorum`) ou le retour d'un nœud (`--node-up`).
+
+Quelque soit la simulation effectué, il est utile d'en sauvegarder l'état de
+sortie grâce à l'argument `--save-output=FICHIER`. Chaque simulation ne crée
+qu'une seule transition. Le fichier obtenu peut donc être réutilisé
+directement en entrée d'une autre simulation afin d'étudier les réactions du
+cluster suite à la défaillance d'une première transition par exemple.
+
+Ces actions restent cependant de simples simulation, à aucun moment l'agent
+n'est exécuté. Ainsi, les éventuels paramètres positionnés par ce dernier
+au cours des opérations ne seront pas positionnés. Vous pouvez néanmoins les
+positionner vous même dans les fichiers XML de simulation à l'aide des outils
+`pcs`, `crm_attribute`, `crm_master`, ...
+
+Enfin, Chaque transition calculée et appliquée en production par le cluster
+est enregistrée localement par le `pengine`. Par exemple, dans les log:
+
+~~~
+pengine: notice: Calculated transition 71, saving inputs in /var/lib/pacemaker/pengine/pe-input-135.bz2
+~~~
+
+Il est possible d'observer le contenu de cette transition très simplement
+grâce à `crm_simulate`, ce qui est utile dans l'analyse d'un événement passé:
+
+~~~console
+# crm_simulate --simulate --xml-file /var/lib/pacemaker/pengine/pe-input-135.bz2
+Using the original execution date of: 2020-03-26 17:30:27Z
+
+Current cluster status:
+[...]
+~~~
+
+:::
+
+-----
+
+## Détection de panne
+
+* perte d'un nœud
+ * détectée par Corosync
+ * immédiatement communiqué à Pacemaker
+ * bascules rapides
+* le temps de détection d'une panne sur la ressource dépend du `monitor interval`
+* la transition calculée dépendent du type et du rôle de la ressource
+* le cluster essaie de redémarrer sur le même nœud si possible
+* pas de failback automatique
+
+::: notes
+
+En cas de panne, la ressource est arrêtée ou déplacée vers un autre nœud
+dans les cas suivants:
+
+* perte totale du nœud où résidait la ressource
+* `failcount` de la ressource supérieur ou égal au `migration-threshold`
+* erreur retournée par l'opération `monitor` de type `hard`
+ (voir [_Ressource Agent_ (_RA_)])
+* perte du quorum pour la partition locale
+
+Dans le cas de la perte du nœud, Corosync détecte très rapidement qu'un membre
+a quitté le groupe brusquement. Il indique immédiatement à Pacemaker que le
+nombre de membre du cluster a changé. La première action de Pacemaker est
+habituellement de déclencher un _fencing_ du nœud disparu, au cas où ce dernier
+ne soit pas réellement éteint ou qu'il puisse revenir inopinément et rendre le
+cluster instable. Les ressources hébergées sur le nœud disparu sont déplacées
+une fois le _fencing_ confirmé.
+
+Dans le cas d'une ressource est défaillante, si l'erreur retournée par
+l'opération a un niveau de criticité `hard` (voir [_Ressource Agent_ (_RA_)]),
+la ressource est démarrée sur un autre nœud.
+
+Dans les autres cas, tant que le `failcount` ne dépasse pas le
+`migration-threshold` de la ressource, le cluster tente de redémarrer cette
+dernière sur le même nœud (`recovery`).
+
+Que la ressource soit redémarrée sur le même nœud ou déplacée ailleurs,
+Pacemaker tente toujours un arrêt (opération `stop`) de celle-ci. Or, si
+l'opération `stop` échoue, elle est "promue" en fencing lors de la transition
+suivante. Ce comportement est dicté par la propriété `on-fail=fence` de
+l'action `stop` (valeur par défaut). Il est __fortement__ déconseillé de
+modifier ce comportement.
+
+Les chapitres suivants présentent les réactions du cluster en fonction du
+rôle de l'instance: secondaire ou primaire.
+
+De plus, Pacemaker n'a pas d'opération de `failback`. Du reste, ce type
+d'opération se prête mal à l'automatisation dans le cadre d'un SGBD. Concernant
+PostgreSQL, la procédure de failback est aussi différente en fonction du
+rôle de l'instance au moment de la défaillance.
+
+:::
+
+-----
+
+## Défaillance d'un secondaire
+
+* transition: `stop` -> `start`
+* cas détecté par l'agent
+ * `notify` pré-stop: phase de recovery de PostgreSQL
+
+::: notes
+
+Un incident sur un standby est traité par le cluster par une action `recovery`
+qui consiste à enchaîner les deux opérations `stop` et `start` ainsi que les
+différentes actions `notify` pré et post opération.
+
+L'agent PAF détecte ces transitions de `recovery` du cluster sur le même nœud.
+Il tente alors de corriger le crash de l'instance locale en la démarrant afin
+que celle-ci puisse effectuer sa phase de _recovery_ usuelle. Cette opération
+est réalisée en tout début de transition durant l'action `notify` pré-stop.
+
+
+
+:::
+
+-----
+
+### TP: Failover d'un secondaire
+
+::: notes
+
+Supprimer toutes éventuelles contraintes temporaires liées aux TP précédents.
+
+Ce TP simule d'abord un incident sur un secondaire, puis compare la simulation
+avec la réalité.
+
+1. positionner le paramètre `migration-threshold` de pgsqld à `2`
+2. créer un fichier de simulation `fail-secondary-0.xml` pour travailler dessus
+3. injecter une erreur `soft` lors du monitor sur la ressource `pgsqld` de
+ `hanode3`. Enregistrer le résultat dans `fail-secondary-1.xml`
+4. envoyer un signal SIGKILL aux processus `postgres` sur `hanode3` et vérifier
+ le comportement simulé
+5. injecter la même erreur en utilisant comme situation de départ
+ `fail-secondary-1.xml`
+6. Tuer une seconde fois les processus `postgres` sur `hanode3`
+7. reproduire en simulation le comportement observé. Enregistrez les
+ résultats dans `fail-secondary-2.xml` puis `fail-secondary-3.xml`
+
+:::
+
+-----
+
+### Correction: Failover d'un secondaire
+
+::: notes
+
+Ce TP simule d'abord un incident sur un secondaire, puis compare la simulation
+avec la réalité.
+
+
+1. positionner le paramètre `migration-threshold` de pgsqld à `2`
+
+~~~console
+# pcs resource update pgsqld meta migration-threshold=2
+~~~
+
+2. créer un fichier de simulation `fail-secondary-0.xml` pour travailler dessus
+
+~~~console
+# pcs cluster cib fail-secondary-0.xml
+~~~
+
+3. injecter une erreur `soft` lors du monitor sur la ressource `pgsqld` de
+ `hanode3`. Enregistrer le résultat dans `fail-secondary-1.xml`
+
+~~~console
+# crm_simulate --simulate \
+ --xml-file=fail-secondary-0.xml \
+ --save-output=fail-secondary-1.xml \
+ --op-inject=pgsqld_monitor_16000@hanode3=1
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+
+Performing requested modifications
+ + Injecting pgsqld_monitor_15000@hanode3=1 into the configuration
+ + Injecting attribute fail-count-pgsqld#monitor_15000=value++ into /node_state '3'
+ + Injecting attribute last-failure-pgsqld#monitor_15000=1585235516 into /node_state '3'
+
+Transition Summary:
+ * Recover pgsqld:0 ( Slave hanode3 )
+
+Executing cluster transition:
+ * Cluster action: clear_failcount for pgsqld on hanode3
+ * Pseudo action: pgsqld-clone_pre_notify_stop_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_stop_0
+ * Pseudo action: pgsqld-clone_stop_0
+ * Resource action: pgsqld stop on hanode3
+ * Pseudo action: pgsqld-clone_stopped_0
+ * Pseudo action: pgsqld-clone_post_notify_stopped_0
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_stopped_0
+ * Pseudo action: pgsqld-clone_pre_notify_start_0
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_start_0
+ * Pseudo action: pgsqld-clone_start_0
+ * Resource action: pgsqld start on hanode3
+ * Pseudo action: pgsqld-clone_running_0
+ * Pseudo action: pgsqld-clone_post_notify_running_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_running_0
+ * Resource action: pgsqld monitor=16000 on hanode3
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+Le cluster redémarre l'instance sur le même nœud. Son `failcount` est
+incrémenté de `1`.
+
+La transition effectue bien une action `stop` suivie d'une action `start`.
+
+~~~console
+# pcs -f fail-secondary-1.xml resource failcount show pgsqld
+Failcounts for resource 'pgsqld'
+ hanode3: 1
+~~~
+
+4. envoyer un signal `SIGKILL` aux processus `postgres` sur `hanode3` et vérifier
+ le comportement simulé
+
+~~~console
+# pkill -SIGKILL postgres
+~~~
+
+Le comportement simulé est bien le même que celui observé.
+
+~~~console
+# pcs resource failcount show pgsqld
+Failcounts for resource 'pgsqld'
+ hanode3: 1
+
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+5. injecter la même erreur en utilisant comme situation de départ
+ `fail-secondary-1.xml`
+
+~~~console
+# crm_simulate --simulate \
+ --xml-file=fail-secondary-1.xml \
+ --save-output=fail-secondary-2.xml \
+ --op-inject=pgsqld_monitor_16000@hanode3=1
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+
+Performing requested modifications
+ + Injecting pgsqld_monitor_16000@hanode3=1 into the configuration
+ + Injecting attribute fail-count-pgsqld#monitor_16000=value++ into /node_state '3'
+ + Injecting attribute last-failure-pgsqld#monitor_16000=1585243357 into /node_state '3'
+
+Transition Summary:
+ * Stop pgsqld:0 ( Slave hanode3 ) due to node availability
+
+Executing cluster transition:
+ * Cluster action: clear_failcount for pgsqld on hanode3
+ * Pseudo action: pgsqld-clone_pre_notify_stop_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_stop_0
+ * Pseudo action: pgsqld-clone_stop_0
+ * Resource action: pgsqld stop on hanode3
+ * Pseudo action: pgsqld-clone_stopped_0
+ * Pseudo action: pgsqld-clone_post_notify_stopped_0
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_stopped_0
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 ]
+ Stopped: [ hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+Le `failcount` ayant atteint la valeur de `migration-threshold`, la ressource
+doit quitter le nœud. Néanmoins, tous les autres nœuds possédant déjà un
+clone et le paramètre `clone-node-max` étant à `1`, ce troisème clone ne peut
+démarrer nulle part.
+
+~~~console
+# pcs -f fail-secondary-2.xml resource failcount show pgsqld
+Failcounts for resource 'pgsqld'
+ hanode3: 2
+~~~
+
+6. Tuer une seconde fois les processus `postgres` sur `hanode3`
+
+~~~console
+# pkill -SIGKILL postgres
+~~~
+
+Cette fois-ci, le comportement est différent. La ressource n'est pas
+simplement isolée, c'est tout le nœud `hanode3` est isolé.
+
+~~~console
+# pcs status nodes
+Pacemaker Nodes:
+ Online: hanode1 hanode2
+ Standby:
+ Maintenance:
+ Offline: hanode3
+[...]
+~~~
+
+Les log de `hanode3` montrent les erreurs suivantes:
+
+~~~
+lrmd[3248]: info: executing - rsc:pgsqld action:stop call_id:85
+pgsqlms(pgsqld): ERROR: Instance "pgsqld" controldata indicates a running secondary instance, the instance has probably crashed
+pgsqlms(pgsqld): ERROR: Unexpected state for instance "pgsqld" (returned 1)
+lrmd[3248]: info: finished - rsc:pgsqld action:stop call_id:85 pid:9962 exit-code:1 exec-time:161ms queue-time:0ms
+~~~
+
+L'agent PAF est très stricte et contrôle l'état de l'instance avant chaque
+opération. Lors de l'opération stop, il détecte que l'instance se trouve
+dans un état incohérent et lève alors une erreur.
+
+À partir de cette erreur, les log du DC présentent les messages suivants:
+
+~~~
+crmd: warning: status_from_rc: Action 2 (pgsqld_stop_0) on hanode3 failed (target: 0 vs. rc: 1): Error
+
+pengine: warning: Processing failed stop of pgsqld:0 on hanode3: unknown error | rc=1
+pengine: warning: Cluster node hanode3 will be fenced: pgsqld:0 failed there
+pengine: warning: Scheduling Node hanode3 for STONITH
+pengine: notice: Stop of failed resource pgsqld:0 is implicit after hanode3 is fenced
+pengine: notice: * Fence (reboot) hanode3 'pgsqld:0 failed there'
+pengine: info: Leave fence_vm_hanode1 (Started hanode2)
+pengine: info: Leave fence_vm_hanode2 (Started hanode1)
+pengine: info: Leave fence_vm_hanode3 (Started hanode1)
+pengine: notice: * Stop pgsqld:0 (Slave hanode3 )
+pengine: info: Leave pgsqld:1 (Master hanode1)
+pengine: info: Leave pgsqld:2 (Slave hanode2)
+pengine: info: Leave pgsql-master-ip (Started hanode1)
+pengine: warning: Calculated transition 75 (with warnings), saving inputs in /var/lib/pacemaker/pengine/pe-warn-0.bz2
+
+crmd: notice: te_fence_node: Requesting fencing (reboot) of node hanode3
+stonith-ng: notice: initiate_remote_stonith_op: Requesting peer fencing (reboot) of hanode3
+stonith-ng: notice: crm_update_peer_state_iter: Node hanode3 state is now lost | nodeid=3 previous=member source=crm_update_peer_proc
+crmd: notice: crm_update_peer_state_iter: Node hanode3 state is now lost
+~~~
+
+Une nouvelle transition est calculée et l'opération `stop` est "promue" en
+fencing.
+
+7. reproduire en simulation le comportement observé. Enregistrez les
+ résultats dans `fail-secondary-2.xml` puis `fail-secondary-3.xml`
+
+~~~console
+# crm_simulate --simulate \
+ --xml-file=fail-secondary-1.xml \
+ --save-output=fail-secondary-2.xml \
+ --op-inject=pgsqld_monitor_16000@hanode3=1 \
+ --op-fail=pgsqld_stop_0@hanode3=1
+[...]
+Performing requested modifications
+ + Injecting pgsqld_monitor_16000@hanode3=1 into the configuration
+ + Injecting attribute fail-count-pgsqld#monitor_16000=value++ into /node_state '3'
+ + Injecting attribute last-failure-pgsqld#monitor_16000=1585245905 into /node_state '3'
+
+Transition Summary:
+ * Stop pgsqld:0 ( Slave hanode3 ) due to node availability
+
+Executing cluster transition:
+ * Cluster action: clear_failcount for pgsqld on hanode3
+ * Pseudo action: pgsqld-clone_pre_notify_stop_0
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_stop_0
+ * Pseudo action: pgsqld-clone_stop_0
+ * Resource action: pgsqld stop on hanode3
+ Pretending action 2 failed with rc=1
+ + Injecting attribute fail-count-pgsqld#stop_0=value++ into /node_state '3'
+ + Injecting attribute last-failure-pgsqld#stop_0=1585245905 into /node_state '3'
+ * Pseudo action: pgsqld-clone_stopped_0
+ * Pseudo action: pgsqld-clone_post_notify_stopped_0
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_stopped_0
+
+Revised cluster status:
+Node hanode3 (3): UNCLEAN (online)
+Online: [ hanode1 hanode2 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ pgsqld (ocf::heartbeat:pgsqlms): FAILED hanode3
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+
+# crm_simulate --simulate \
+ --xml-file=fail-secondary-2.xml \
+ --save-output=fail-secondary-3.xml
+
+Current cluster status:
+Node hanode3 (3): UNCLEAN (online)
+Online: [ hanode1 hanode2 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ pgsqld (ocf::heartbeat:pgsqlms): FAILED hanode3
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+
+Transition Summary:
+ * Fence (reboot) hanode3 'pgsqld:0 failed there'
+ * Stop pgsqld:0 ( Slave hanode3 ) due to node availability
+
+Executing cluster transition:
+ * Pseudo action: pgsqld-clone_pre_notify_stop_0
+ * Fencing hanode3 (reboot)
+ * Pseudo action: pgsqld_post_notify_stop_0
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_stop_0
+ * Pseudo action: pgsqld-clone_stop_0
+ * Pseudo action: pgsqld_stop_0
+ * Pseudo action: pgsqld-clone_stopped_0
+ * Pseudo action: pgsqld-clone_post_notify_stopped_0
+ * Resource action: pgsqld notify on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_stopped_0
+ * Pseudo action: pgsqld_notified_0
+
+Revised cluster status:
+Online: [ hanode1 hanode2 ]
+OFFLINE: [ hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 ]
+ Stopped: [ hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+:::
+
+-----
+
+## Failback d'un secondaire
+
+* suite à un incident sur la ressource ou la perte de son nœud
+* état incohérent de l'instance: statut différent du `pg_control`
+* PAF lève une erreur systématiquement pour toutes les opérations
+* une erreur sur l'action `stop` conduit à un fencing
+* conclusion: placer l'instance dans un état stable
+1. positionner la ressource en `is-managed=false`
+2. ré-intégrer le nœud dans le cluster
+3. démarrer la ressource manuellement, puis l'arrêter (état stable)
+4. effectuer un `refresh` de la ressource
+5. positionner `is-managed=true` pour la ressource
+
+::: notes
+
+Suite au crash d'une instance secondaire, si le cluster n'a pas réussi à
+l'arrêter localement, le serveur entier a dû être isolé (cf TP
+[Correction: Défaillance d'un secondaire]). L'instance est alors dans un état
+instable: son fichier interne `pg_control` indique un statut `in archive
+recovery` alors que cette dernière n'est pas démarrée et n'accepte aucune
+connexion.
+
+Dans cette situation, l'agent retourne une erreur pour toutes les opérations.
+Au démarrage du cluster sur le nœud concerné, ce dernier va vouloir
+contrôler l'état des ressources sur ce nœud et l'opération de `probe`
+(l'opération `monitor` non récurrente) va retourner une erreur.
+
+Il est même possible que le cluster tente d'effectuer un `recovery` de la
+ressource en effectuant les opérations `stop` puis `start`. Dans ce cas là,
+le nœud se fait une nouvelle fois isoler.
+
+Pour ré-intégrer le nœud et la ressource, l'idéal est de suivre la
+procédure suivante:
+
+1. positionner `is-managed=false` pour la ressource
+2. démarrer le cluster sur le nœud à ré-intégrer
+3. démarrer manuellement l'instance sur le nœud
+4. valider que cette dernière réplique correctement
+5. arrêter l'instance
+6. effectuer une commande `refresh` de la ressource
+7. supprimer `is-managed=false` pour la ressource
+
+Pour plus de facilité, il est possible d'utiliser ici `systemctl` pour
+démarrer et arrêter la ressource. L'important est qu'en fin de procédure,
+`systemd` ne voit pas l'instance comme étant démarrée de son point vue,
+cette dernière étant gérée non pas par lui mais par Pacemaker.
+
+:::
+
+-----
+
+### TP: Failback d'un secondaire
+
+::: notes
+
+1. désactiver la gestion du cluster de `pgsqld-clone`
+2. démarrer le cluster sur `hanode3`
+3. démarrer manuellement l'instance PostgreSQL sur `hanode3`
+4. valider que cette dernière réplique correctement
+5. arrêter l'instance
+6. effectuer une commande `refresh` de `pgsqld`
+7. supprimer `is-managed=false` pour la ressource
+
+:::
+
+-----
+
+### Correction: Failback d'un secondaire
+
+::: notes
+
+1. désactiver la gestion du cluster de `pgsqld-clone`
+
+~~~console
+# pcs resource unmanage pgsqld-clone
+~~~
+
+2. démarrer le cluster sur `hanode3`
+
+~~~console
+# pcs cluster start
+~~~
+
+Attendre que le nœud soit bien ré-intégré dans le cluster.
+
+3. démarrer manuellement l'instance PostgreSQL sur `hanode3`
+
+~~~console
+# systemctl start postgresql-12
+~~~
+
+4. valider que cette dernière réplique correctement
+
+Depuis l'instance primaire, la ressource est détectée comme démarrée et
+PostgreSQL nous indique qu'elle réplique correctement:
+
+~~~console
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode2 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode3 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode1 (unmanaged)
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+
+# sudo -iu postgres psql
+postgres=# select state, application_name
+ from pg_stat_replication
+ where application_name = 'hanode3';
+ state | application_name
+-----------+------------------
+ streaming | hanode3
+(1 row)
+~~~
+
+5. arrêter l'instance
+
+~~~console
+# systemctl stop postgresql-12
+# systemctl show -p ActiveState postgresql-12
+ActiveState=inactive
+~~~
+
+Après vérification, plus aucun processus `postgres` n'est démarré. Son
+statut est cohérent:
+
+~~~console
+# /usr/pgsql-12/bin/pg_controldata /var/lib/pgsql/12/data/|grep state
+Database cluster state: shut down in recovery
+~~~
+
+6. effectuer une commande `refresh` de `pgsqld`
+
+~~~console
+# pcs resource failcount show pgsqld hanode3
+Failcounts for resource 'pgsqld' on node 'hanode3'
+ hanode3: 3
+
+# pcs resource refresh pgsqld --node=hanode3
+Cleaned up pgsqld:0 on hanode3
+Cleaned up pgsqld:1 on hanode3
+Cleaned up pgsqld:2 on hanode3
+
+ * The configuration prevents the cluster from stopping or starting 'pgsqld-clone' (unmanaged)
+Waiting for 3 replies from the CRMd... OK
+
+# pcs resource failcount show pgsqld hanode3
+No failcounts for resource 'pgsqld' on node 'hanode3'
+~~~
+
+Toutes les erreurs sont supprimées et le failcount est remis à 0.
+
+7. supprimer `is-managed=false` pour la ressource
+
+~~~console
+# pcs resource manage pgsqld-clone
+~~~
+
+La ressource est démarrée sur `hanode3`.
+
+:::
+
+-----
+
+## Défaillance du primaire
+
+1. transaction calculée
+ * `demote` -> `stop` -> `start` -> `promote`
+2. fencing du nœud hébergeant l'instance primaire en échec si nécessaire
+3. si migration, promotion du secondaire avec le meilleur master score
+ 1. le secondaire désigné compare les `LSN` des secondaires
+ 2. poursuite de la promotion s'il est toujours le plus avancé
+ 3. sinon, annulation de la promotion et nouvelle transition
+
+::: notes
+
+En cas d'incident concernant l'instance primaire, la transition calculée
+effectue les quatre opérations suivantes dans cet ordre: `demote`, `stop`,
+`start` et `promote`. Ici aussi, les différentes actions `notify` pré et post
+opération sont bien entendu exécutées.
+
+Comme pour un secondaire, l'agent PAF détecte une transition effectuant ces
+opérations sur l'instance primaire sur un même nœud. Dans ce cas là, l'agent
+tente alors de corriger le crash de l'instance locale en la démarrant afin que
+celle-ci puisse effectuer sa phase de _recovery_ usuelle. Cette opération est
+réalisée en tout début de transition durant l'action `notify` pré-demote.
+
+
+
+Le choix de l'instance à promouvoir se fait en fonction des derniers master
+scores connus. Afin de s'assurer que le secondaire désigné est bien toujours le
+plus avancé dans la réplication, une élection est cependant déclenchée. En
+voici les étapes:
+
+1. opération `notify` pré-promote: chaque secondaire positionne son `LSN`
+ courant dans un attribut de nœud
+2. opération `promote`: l'instance désignée pour la promotion vérifie qu'il a
+ bien le LSN le plus avancé
+3. si un LSN plus avancé est trouvé:
+ * il positionne son master score à `1`
+ * il positionne le master score du secondaire plus avancé à `1000`
+ * il lève une erreur
+ * la transition est annulée et une nouvelle est calculée
+ * retour à l'étape 1.
+
+
+
+:::
+
+-----
+
+### TP: Failover du primaire
+
+::: notes
+
+1. simuler une erreur `soft` pour `pgsqld-clone` sur `hanode1`
+2. tuer tous les processus PostgreSQL avec un signal `KILL`
+3. étudier la réaction du cluster
+4. nettoyer les `failcount` de `pgsqld-clone`
+5. simuler une erreur `OCF_ERR_ARGS` sur `pgsqld-clone`
+6. supprimer le fichier `/var/lib/pgsql/12/data/global/pg_control` sur `hanode1`
+7. étudier la réaction du cluster
+
+:::
+
+-----
+
+### Correction: Failover du primaire
+
+::: notes
+
+1. simuler une erreur `soft` pour `pgsqld-clone` sur `hanode1`
+
+~~~console
+# crm_simulate --simulate --live --op-inject=pgsqld_monitor_15000@hanode1=1
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+
+Performing requested modifications
+ + Injecting pgsqld_monitor_15000@hanode1=1 into the configuration
+ + Injecting attribute fail-count-pgsqld#monitor_15000=value++ into /node_state '1'
+ + Injecting attribute last-failure-pgsqld#monitor_15000=1585328861 into /node_state '1'
+
+Transition Summary:
+ * Recover pgsqld:2 ( Master hanode1 )
+
+Executing cluster transition:
+ * Cluster action: clear_failcount for pgsqld on hanode1
+ * Pseudo action: pgsqld-clone_pre_notify_demote_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_demote_0
+ * Pseudo action: pgsqld-clone_demote_0
+ * Resource action: pgsqld demote on hanode1
+ * Pseudo action: pgsqld-clone_demoted_0
+ * Pseudo action: pgsqld-clone_post_notify_demoted_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_demoted_0
+ * Pseudo action: pgsqld-clone_pre_notify_stop_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_stop_0
+ * Pseudo action: pgsqld-clone_stop_0
+ * Resource action: pgsqld stop on hanode1
+ * Pseudo action: pgsqld-clone_stopped_0
+ * Pseudo action: pgsqld-clone_post_notify_stopped_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_stopped_0
+ * Pseudo action: pgsqld-clone_pre_notify_start_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_start_0
+ * Pseudo action: pgsqld-clone_start_0
+ * Resource action: pgsqld start on hanode1
+ * Pseudo action: pgsqld-clone_running_0
+ * Pseudo action: pgsqld-clone_post_notify_running_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_running_0
+ * Pseudo action: pgsqld-clone_pre_notify_promote_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_promote_0
+ * Pseudo action: pgsqld-clone_promote_0
+ * Resource action: pgsqld promote on hanode1
+ * Pseudo action: pgsqld-clone_promoted_0
+ * Pseudo action: pgsqld-clone_post_notify_promoted_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_promoted_0
+ * Resource action: pgsqld monitor=15000 on hanode1
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+~~~
+
+Un `recover` est planifié pour `pgsqld` sur `hanode1`. Ce dernier correspond
+aux opérations suivantes dans cet ordre:
+
+Action Sub-action Nœud(s)
+---------- ------------ ---------------------------------
+ `notify` pre-demote `hanode1`, `hanode2`, `hanode3`
+ `demote` N/A `hanode1`
+ `notify` post-demote `hanode1`, `hanode2`, `hanode3`
+ `notify` pre-stop `hanode1`, `hanode2`, `hanode3`
+ `stop` N/A `hanode1`
+ `notify` post-stop `hanode2`, `hanode3`
+ `notify` pre-start `hanode2`, `hanode3`
+ `start` N/A `hanode1`
+ `notify` post-start `hanode1`, `hanode2`, `hanode3`
+ `notify` pre-promote `hanode1`, `hanode2`, `hanode3`
+ `promote` N/A `hanode1`
+ `notify` post-promote `hanode1`, `hanode2`, `hanode3`
+
+2. tuer tous les processus PostgreSQL avec un signal `KILL`
+
+~~~console
+# pkill -SIGKILL postgres
+~~~
+
+3. étudier la réaction du cluster
+
+L'agent `pgsqlms` détecte que l'instance a a été interrompue brusquement:
+
+~~~
+pgsqlms(pgsqld): DEBUG: _confirm_stopped: no postmaster process found for instance "pgsqld"
+pgsqlms(pgsqld): DEBUG: _controldata: instance "pgsqld" state is "in production"
+pgsqlms(pgsqld): ERROR: Instance "pgsqld" controldata indicates a running primary instance, the instance has probably crashed
+~~~
+
+En réaction, `pengine` décide de redémarrer l'instance sur le même nœud
+(sur le DC):
+
+~~~
+pengine: info: Start recurring monitor (15s) for pgsqld:1 on hanode1
+pengine: info: Leave fence_vm_hanode1 (Started hanode2)
+pengine: info: Leave fence_vm_hanode2 (Started hanode1)
+pengine: info: Leave fence_vm_hanode3 (Started hanode1)
+pengine: info: Leave pgsqld:0 (Slave hanode2 )
+pengine: notice: * Recover pgsqld:1 (Master hanode1 )
+pengine: info: Leave pgsqld:2 (Slave hanode3 )
+pengine: info: Leave pgsql-master-ip (Started hanode1)
+~~~
+
+Durant l'opération `notify` pré-demote, l'agent tente un recovery de
+l'instance afin de la remettre en ordre de marche:
+
+~~~
+pgsqlms(pgsqld): INFO: Trying to start failing master "pgsqld"...
+[...]
+pgsqlms(pgsqld): INFO: State is "in production" after recovery attempt
+~~~
+
+Le reste de la transition se déroule comme prévu et l'instance revient bien
+en production. Le comportement est bien le même que celui simulé. Voici les
+actions déclenchées par le DC (log remis en forme):
+
+~~~
+# grep -E 'crmd:.*Initiating' /var/log/cluster/corosync.log
+[...]
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode1
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode2
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode3
+
+crmd: notice: Initiating demote pgsqld_demote_0 locally on hanode1
+
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode1
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode2
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode3
+
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode1
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode2
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode3
+
+crmd: notice: Initiating stop pgsqld_stop_0 locally on hanode1
+
+crmd: notice: Initiating notify pgsqld_post_notify_stop_0 on hanode2
+crmd: notice: Initiating notify pgsqld_post_notify_stop_0 on hanode3
+
+crmd: notice: Initiating notify pgsqld_pre_notify_start_0 on hanode2
+crmd: notice: Initiating notify pgsqld_pre_notify_start_0 on hanode3
+
+crmd: notice: Initiating start pgsqld_start_0 locally on hanode1
+
+crmd: notice: Initiating notify pgsqld_post_notify_start_0 on hanode1
+crmd: notice: Initiating notify pgsqld_post_notify_start_0 on hanode2
+crmd: notice: Initiating notify pgsqld_post_notify_start_0 on hanode3
+
+crmd: notice: Initiating notify pgsqld_pre_notify_promote_0 on hanode1
+crmd: notice: Initiating notify pgsqld_pre_notify_promote_0 on hanode2
+crmd: notice: Initiating notify pgsqld_pre_notify_promote_0 on hanode3
+
+crmd: notice: Initiating promote pgsqld_promote_0 locally on hanode1
+
+crmd: notice: Initiating notify pgsqld_post_notify_promote_0 on hanode1
+crmd: notice: Initiating notify pgsqld_post_notify_promote_0 on hanode2
+crmd: notice: Initiating notify pgsqld_post_notify_promote_0 on hanode3
+~~~
+
+4. nettoyer les `failcount` de `pgsqld-clone`
+
+~~~console
+# pcs resource failcount reset pgsqld
+~~~
+
+5. simuler une erreur `OCF_ERR_ARGS` sur `pgsqld-clone`
+
+Le code retour `OCF_ERR_ARGS` correspond à une erreur de niveau `hard`. Ainsi,
+bien que le `migration-threshold` ne soit pas atteint, le cluster doit basculer
+l'instance ailleurs.
+
+~~~console
+# crm_simulate --simulate --live --op-inject=pgsqld_monitor_15000@hanode1=2
+
+Current cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode1 ]
+ Slaves: [ hanode2 hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode1
+
+Performing requested modifications
+ + Injecting pgsqld_monitor_15000@hanode1=2 into the configuration
+ + Injecting attribute fail-count-pgsqld#monitor_15000=value++ into /node_state '1'
+ + Injecting attribute last-failure-pgsqld#monitor_15000=1585330828 into /node_state '1'
+
+Transition Summary:
+ * Promote pgsqld:0 ( Slave -> Master hanode2 )
+ * Stop pgsqld:2 ( Master hanode1 ) due to node availability
+ * Move pgsql-master-ip ( hanode1 -> hanode2 )
+
+Executing cluster transition:
+ * Resource action: pgsqld cancel=16000 on hanode2
+ * Cluster action: clear_failcount for pgsqld on hanode1
+ * Pseudo action: pgsqld-clone_pre_notify_demote_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_demote_0
+ * Pseudo action: pgsqld-clone_demote_0
+ * Resource action: pgsqld demote on hanode1
+ * Pseudo action: pgsqld-clone_demoted_0
+ * Pseudo action: pgsqld-clone_post_notify_demoted_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_demoted_0
+ * Pseudo action: pgsqld-clone_pre_notify_stop_0
+ * Resource action: pgsql-master-ip stop on hanode1
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Resource action: pgsqld notify on hanode1
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_stop_0
+ * Pseudo action: pgsqld-clone_stop_0
+ * Resource action: pgsqld stop on hanode1
+ * Pseudo action: pgsqld-clone_stopped_0
+ * Pseudo action: pgsqld-clone_post_notify_stopped_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_stopped_0
+ * Pseudo action: pgsqld-clone_pre_notify_promote_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Pseudo action: pgsqld-clone_confirmed-pre_notify_promote_0
+ * Pseudo action: pgsqld-clone_promote_0
+ * Resource action: pgsqld promote on hanode2
+ * Pseudo action: pgsqld-clone_promoted_0
+ * Pseudo action: pgsqld-clone_post_notify_promoted_0
+ * Resource action: pgsqld notify on hanode2
+ * Resource action: pgsqld notify on hanode3
+ * Pseudo action: pgsqld-clone_confirmed-post_notify_promoted_0
+ * Resource action: pgsql-master-ip start on hanode2
+ * Resource action: pgsqld monitor=15000 on hanode2
+ * Resource action: pgsql-master-ip monitor=10000 on hanode2
+
+Revised cluster status:
+Online: [ hanode1 hanode2 hanode3 ]
+
+ fence_vm_hanode1 (stonith:fence_virsh): Started hanode2
+ fence_vm_hanode2 (stonith:fence_virsh): Started hanode1
+ fence_vm_hanode3 (stonith:fence_virsh): Started hanode1
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ Masters: [ hanode2 ]
+ Slaves: [ hanode3 ]
+ Stopped: [ hanode1 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode2
+~~~
+
+6. supprimer le fichier `/var/lib/pgsql/12/data/global/pg_control` sur `hanode1`
+
+~~~console
+# rm -f /var/lib/pgsql/12/data/global/pg_control
+~~~
+
+7. étudier la réaction du cluster
+
+Le cluster prévoie la même transition que celle simulée. Cependant, à cause
+de l'état incohérent de l'instance, les opération `demote` et `stop`
+interrompent deux transitions et la dernière erreur provoque l'isolation de
+`hanode1`.
+
+Première transition, correspondant à ce qui avait été simulé:
+
+~~~
+pengine: notice: * Stop pgsqld:0 ( Master hanode1 )
+pengine: info: Leave pgsqld:1 ( Slave hanode3 )
+pengine: notice: * Promote pgsqld:2 ( Slave -> Master hanode2 )
+pengine: notice: * Move pgsql-master-ip ( hanode1 -> hanode2 )
+
+crmd: debug: Unpacked transition 136: 41 actions in 41 synapses
+
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode1
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode2
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode3
+
+crmd: notice: Initiating demote pgsqld_demote_0 on hanode1
+crmd: warning: Action 15 (pgsqld_demote_0) on hanode2 failed
+
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode1
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode2
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode3
+~~~
+
+La seconde transition prévoit de terminer l'arrêt de l'instance sur `hanode1`
+puis d'effectuer la promotion sur `hanode2`. Elle termine en erreur sur
+l'opération `stop`:
+
+~~~
+pengine: notice: * Stop pgsqld:0 ( Slave hanode1 )
+pengine: info: Leave pgsqld:1 ( Slave hanode3 )
+pengine: notice: * Promote pgsqld:2 ( Slave -> Master hanode2 )
+pengine: notice: * Stop pgsql-master-ip ( hanode1 )
+
+crmd: debug: Unpacked transition 137: 24 actions in 24 synapses
+
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode1
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode2
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode3
+
+crmd: notice: Initiating stop pgsqld_stop_0 on hanode1
+crmd: warning: Action 3 (pgsqld_stop_0) on hanode1 failed
+
+crmd: notice: Initiating notify pgsqld_post_notify_stop_0 on hanode3
+crmd: notice: Initiating notify pgsqld_post_notify_stop_0 on hanode2
+~~~
+
+La troisième transition prévoie d'isoler `hanode1` afin de s'assurer que
+l'instance est bien arrêtée, puis de promouvoir l'instance sur `hanode2` et y
+déplacer l'adresse IP virtuelle. Cette dernière arrive au bout:
+
+~~~
+pengine: notice: * Fence (reboot) hanode2 'pgsqld:0 failed there'
+pengine: notice: * Stop pgsqld:0 ( Master hanode1 )
+pengine: info: Leave pgsqld:1 ( Slave hanode3 )
+pengine: notice: * Promote pgsqld:2 ( Slave -> Master hanode2 )
+pengine: notice: * Move pgsql-master-ip ( hanode2 -> hanode2 )
+
+crmd: debug: Unpacked transition 138: 43 actions in 43 synapses
+
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode3
+crmd: notice: Initiating notify pgsqld_pre_notify_demote_0 on hanode2
+
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode3
+crmd: notice: Initiating notify pgsqld_post_notify_demote_0 on hanode2
+
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode3
+crmd: notice: Initiating notify pgsqld_pre_notify_stop_0 on hanode2
+
+crmd: notice: Initiating notify pgsqld_post_notify_stop_0 on hanode3
+crmd: notice: Initiating notify pgsqld_post_notify_stop_0 on hanode2
+
+crmd: notice: Initiating notify pgsqld_pre_notify_promote_0 on hanode3
+crmd: notice: Initiating notify pgsqld_pre_notify_promote_0 on hanode2
+
+crmd: notice: Initiating promote pgsqld_promote_0 on hanode2
+
+crmd: notice: Initiating notify pgsqld_post_notify_promote_0 on hanode3
+crmd: notice: Initiating notify pgsqld_post_notify_promote_0 on hanode2
+~~~
+
+Dans les log, nous trouvons aussi les traces de l'élection qui a lieu entre
+`hanode2` et `hanode3`:
+
+~~~
+attrd: info:Setting lsn_location-pgsqld[hanode2]: (null) -> 21#100672008
+attrd: info:Setting lsn_location-pgsqld[hanode3]: (null) -> 21#100672008
+[...]
+pgsqlms(pgsqld): DEBUG: checking if current node is the best candidate for promotion
+pgsqlms(pgsqld): DEBUG: comparing with "hanode3": TL#LSN is 21#100672008
+pgsqlms(pgsqld): INFO: Promote complete
+~~~
+
+:::
+
+
+-----
+
+## Failback du primaire
+
+* suite à un incident sur la ressource ou la perte de son nœud
+* même problématique que pour un secondaire
+* l'instance doit en plus être reconstruite en secondaire
+* le reste de la procédure est similaire au failback d'un secondaire
+
+::: notes
+
+Suite à la perte brutale d'une instance primaire, le cluster bascule le rôle
+`Master` sur le meilleur secondaire disponible. Néanmoins, il est possible que
+l'ancien primaire possède toujours des données qui n'avaient pas été
+répliquées. Dans ces circonstances, il n'est pas recommandé de rattacher
+directement l'ancien primaire au nouveau. Il est nécessaire de le
+"resynchroniser".
+
+Différentes méthodes sont disponibles mais ne sont pas abordées dans ce
+document. Par exemple: `pg_rewind`, restauration _PITR_ ou `pg_basebackup`.
+
+Une fois l'instance resynchronisée, le reste de la procédure est identique à
+celle détaillée dans le chapitre [Failback d'un secondaire]:
+
+1. re-synchroniser l'instance sur le nœud
+2. positionner `is-managed=false` pour la ressource
+3. démarrer le cluster sur le nœud à ré-intégrer
+4. démarrer manuellement l'instance sur le nœud
+5. valider que cette dernière réplique correctement
+6. arrêter l'instance
+7. effectuer une commande `refresh` de la ressource
+8. supprimer `is-managed=false` pour la ressource
+
+Pour plus de facilité, il est possible d'utiliser ici `systemctl` pour
+démarrer et arrêter la ressource. L'important est qu'en fin de procédure,
+`systemd` ne voit pas l'instance comme étant démarrée de son point vue,
+cette dernière étant gérée non pas par lui mais par Pacemaker.
+
+:::
+
+-----
+
+### TP: Failback du primaire
+
+::: notes
+
+1. re-synchroniser l'instance `hanode1`
+2. désactiver la gestion du cluster de `pgsqld-clone`
+3. démarrer le cluster sur `hanode1`
+4. démarrer manuellement l’instance PostgreSQL sur `hanode1`
+5. valider que cette dernière réplique correctement
+6. arrêter l’instance sur `hanode1`
+7. effectuer une commande `refresh` de `pgsqld`
+8. supprimer `is-managed=false` pour la ressource
+
+:::
+
+-----
+
+### Correction: Failback du primaire
+
+::: notes
+
+1. re-synchroniser l'instance `hanode1`
+
+~~~console
+# su - postgres
+$ rm -r ~postgres/12/data/*
+$ /usr/pgsql-12/bin/pg_basebackup -h 10.20.30.5 -D ~postgres/12/data/ -P
+$ touch ~postgres/12/data/standby.signal
+~~~
+
+NB: le paramètre `primary_conninfo` ou le fichier `pg_hba.conf` n'ont pas à
+être corrigés, ces derniers étant positionnés en dehors du `PGDATA`.
+
+2. désactiver la gestion du cluster de `pgsqld-clone`
+
+~~~console
+# pcs resource unmanage pgsqld-clone
+~~~
+
+3. démarrer le cluster sur `hanode1`
+
+~~~console
+# pcs cluster start
+~~~
+
+4. démarrer manuellement l’instance PostgreSQL sur `hanode1`
+
+~~~console
+# systemctl start postgresql-12
+~~~
+
+5. valider que cette dernière réplique correctement
+
+Depuis `hanode2`, la ressource n'est détectée comme démarrée, cette
+dernière étant arrêté lors du démarrage du cluster sur `hanode1`. Le nœud
+ayant été redémarré, il n'y a pas non plus d'opération `monitor`
+récurrente pour `pgsqld` sur `hanode1`.
+
+~~~console
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ pgsqld (ocf::heartbeat:pgsqlms): Master hanode2 (unmanaged)
+ pgsqld (ocf::heartbeat:pgsqlms): Slave hanode3 (unmanaged)
+ Stopped: [ hanode1 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode2
+
+# sudo -iu postgres psql
+postgres=# select state, application_name
+ from pg_stat_replication
+ where application_name = 'hanode1';
+ state | application_name
+-----------+------------------
+ streaming | hanode1
+
+(1 row)
+~~~
+
+6. arrêter l’instance sur `hanode1`
+
+~~~console
+# systemctl stop postgresql-12
+~~~
+
+Attendre que Pacemaker détecte l'arrêt de l'instance.
+
+7. effectuer une commande `refresh` de `pgsqld`
+
+~~~console
+# pcs resource failcount show pgsqld hanode1
+Failcounts for resource 'pgsqld' on node 'hanode1'
+ hanode1: 2
+
+# pcs resource refresh pgsqld --node=hanode1
+Cleaned up pgsqld:0 on hanode1
+Cleaned up pgsqld:1 on hanode1
+Cleaned up pgsqld:2 on hanode1
+
+ * The configuration prevents the cluster from stopping or starting 'pgsqld-clone' (unmanaged)
+Waiting for 3 replies from the CRMd... OK
+
+# pcs resource failcount show pgsqld hanode1
+No failcounts for resource 'pgsqld' on node 'hanode1'
+~~~
+
+8. supprimer `is-managed=false` pour la ressource
+
+~~~console
+# pcs resource manage pgsqld-clone
+~~~
+
+:::
+
+-----
+
+## Détails d'un switchover
+
+* opération planifiée
+* macro-procédure:
+ 1. arrêt propre de l'instance primaire
+ 2. redémarrage de l'instance primaire en secondaire
+ 3. vérification du secondaire désigné
+ 4. élection et promotion du secondaire
+
+::: notes
+
+Dans le cadre de cette formation, un _switchover_ désigne la promotion
+contrôlée d'une instance secondaire et le raccrochage de l'ancien primaire en
+tant que secondaire, sans reconstruction.
+
+Le switchover s'appuie sur la procédure standard de PostgreSQL pour effectuer
+la bascule.:
+
+* __Rétrograder le primaire__
+
+ Cette étape consiste à éteindre l'instance primaire et la redémarrer en tant
+ que secondaire. Avant qu'elle ne s'arrête, l'instance primaire envoie tous
+ les journaux de transactions nécessaires aux secondaires **connectées**.
+
+ Cette étape est effectuée durant l'opération `demote`.
+* __Contrôle du secondaire__
+
+ Cette étape consiste à vérifier sur le secondaire que tous les journaux de
+ transaction de l'ancien primaire ont bien été reçu, jusqu'au `shutdown
+ checkpoint`.
+
+ L'agent interrompt la transition en cas d'échec de ces contrôle. Le cluster
+ décide alors que faire en fonction des contraintes en place.
+
+ Cette étape est réalisée lors de l'opération `notify` exécutée juste
+ avant la promotion.
+* __Promotion du secondaire__
+
+ Exécution de `pg_ctl promote` sur l'instance secondaire. Cette étape est
+ réalisée par l'opération `promote`.
+
+Le choix du secondaire à promouvoir dépend de la procédure choisie pour
+déplacer le rôle. Il existe deux méthodes pour demander au cluster de
+déplacer le rôle `Master` vers un autre nœud.
+
+La première consiste à bannir le rôle `Master` de son emplacement actuel.
+Cela implique de positionner une contrainte location `-INFINITY` pour le
+rôle `Master` sur son nœud courant. Attention, la contrainte concerne bien
+le rôle et non la ressource ! Dans cette situation, le cluster choisi et
+promeut alors le clone avec le master score le plus élevé. Cette procédure
+se traduit avec les commandes `pcs` suivantes:
+
+~~~
+pcs resource ban --master
+# ou
+pcs resource move --master
+~~~
+
+La seconde méthode consiste à imposer l'emplacement du rôle `Master` avec
+une contrainte de location `INFINITY` sur un nœud. Cette procédure
+se traduit avec la commande `pcs` suivante:
+
+~~~
+pcs resource move --master
+~~~
+
+Dans ces commandes, `` désigne la ressource multi-state et non
+le nom des clones.
+
+Dans les deux cas, il faut penser à supprimer ces contraintes après le
+switchover avec la commande `pcs resource clear `.
+L'utilisation de l'option `resource-stickiness` au niveau du cluster ou des
+ressources permet à la ressource de rester sur son nouveau nœud après la
+suppression de la contrainte de localisation.
+
+:::
+
+-----
+
+### TP: Switchover
+
+::: notes
+
+1. provoquer une bascule vers le nœud `hanode2`
+2. afficher les contraintes pour la ressource `pgsqld-clone`
+3. observer les scores au sein du cluster
+4. retirer la contrainte positionnée par la bascule
+5. observer la transition proposée dans les log du DC
+6. répéter les même opérations en effectuant la bascule avec chacune des
+ commandes suivantes :
+
+~~~
+pcs resource move pgsqld-clone --master
+pcs resource ban pgsqld-clone --master
+~~~
+
+Pour chacune, observer :
+
+* les contraintes posées par `pcs`
+* le statut de la ressource sur le nœud où la contrainte est posée
+
+7. retirer les contraintes des commandes précédentes sur la ressource
+
+:::
+
+-----
+
+### Correction: Switchover
+
+::: notes
+
+
+1. provoquer une bascule vers le nœud `hanode3`
+
+~~~console
+# pcs resource move --master --wait pgsqld-clone hanode3
+Resource 'pgsqld-clone' is master on node hanode3; slave on nodes hanode1, hanode2.
+~~~
+
+2. afficher les contraintes pour la ressource `pgsqld-clone`
+
+~~~console
+# pcs constraint location show resource pgsqld-clone
+Location Constraints:
+ Resource: pgsqld-clone
+ Enabled on: hanode3 (score:INFINITY) (role: Master)
+~~~
+
+Une constrainte de localisation avec un poid `INFINITY` a été créée pour le
+rôle `Master` de `pgsqld-clone` sur `hanode2`.
+
+3. observer les scores au sein du cluster
+
+~~~console
+# crm_simulate -sL|grep 'promotion score'
+pgsqld:0 promotion score on hanode3: INFINITY
+pgsqld:2 promotion score on hanode1: 1000
+pgsqld:1 promotion score on hanode2: 990
+
+~~~
+
+Cette contrainte de localisation influence directement le score de promotion
+calculé.
+
+4. retirer la contrainte positionnée par la bascule
+
+~~~console
+# pcs resource clear pgsqld-clone
+
+# crm_simulate -sL|grep "promotion score"
+pgsqld:0 promotion score on hanode3: 1003
+pgsqld:2 promotion score on hanode1: 1000
+pgsqld:1 promotion score on hanode2: 990
+
+# pcs constraint location show resource pgsqld-clone
+Location Constraints:
+~~~
+
+La situation revient à la normale et l'instance principale reste à son
+nouvel emplacement.
+
+5. observer la transition proposée dans les log du DC
+
+~~~
+pengine: debug: Allocating up to 3 pgsqld-clone instances to a possible 3 nodes (at most 1 per host, 1 optimal)
+pengine: debug: Assigning hanode1 to pgsqld:1
+pengine: debug: Assigning hanode2 to pgsqld:2
+pengine: debug: Assigning hanode3 to pgsqld:0
+pengine: debug: Allocated 3 pgsqld-clone instances of a possible 3
+pengine: debug: pgsqld:0 master score: 1000000
+pengine: info: Promoting pgsqld:0 (Slave hanode3)
+pengine: debug: pgsqld:1 master score: 1001
+pengine: debug: pgsqld:2 master score: 990
+pengine: info: pgsqld-clone: Promoted 1 instances of a possible 1 to master
+pengine: debug: Assigning hanode3 to pgsql-master-ip
+pengine: info: Start recurring monitor (15s) for pgsqld:0 on hanode3
+pengine: info: Cancelling action pgsqld:0_monitor_16000 (Slave vs. Master)
+pengine: info: Cancelling action pgsqld:1_monitor_15000 (Master vs. Slave)
+pengine: info: Start recurring monitor (16s) for pgsqld:1 on hanode1
+pengine: info: Start recurring monitor (15s) for pgsqld:0 on hanode3
+pengine: info: Start recurring monitor (16s) for pgsqld:1 on hanode2
+pengine: info: Start recurring monitor (10s) for pgsql-master-ip on hanode3
+pengine: info: Leave fence_vm_hanode1 (Started hanode2)
+pengine: info: Leave fence_vm_hanode2 (Started hanode1)
+pengine: info: Leave fence_vm_hanode3 (Started hanode1)
+pengine: notice: * Promote pgsqld:0 (Slave -> Master hanode3)
+pengine: notice: * Demote pgsqld:1 (Master -> Slave hanode2)
+pengine: info: Leave pgsqld:2 (Slave hanode1 )
+pengine: notice: * Move pgsql-master-ip (hanode2 -> hanode3 )
+~~~
+
+6. répéter les même opérations en effectuant la bascule avec chacune des
+ commandes suivantes :
+
+~~~
+pcs resource move pgsqld-clone --master
+pcs resource ban pgsqld-clone --master
+~~~
+
+Ces deux commandes sont similaires. Dans les deux cas, une contrainte de
+localisation avec un score `-INFINITY` est positionnée pour le rôle `Master`
+sur le nœud l'hébergeant.
+
+~~~console
+# pcs resource ban --master --wait pgsqld-clone
+Warning: Creating location constraint cli-ban-pgsqld-clone-on-hanode1 with a score of -INFINITY for resource pgsqld-clone on node hanode1.
+This will prevent pgsqld-clone from being promoted on hanode1 until the constraint is removed. This will be the case even if hanode1 is the last node in the cluster.
+Resource 'pgsqld-clone' is master on node hanode2; slave on nodes hanode1, hanode3.
+
+# pcs constraint location show resource pgsqld-clone
+Location Constraints:
+ Resource: pgsqld-clone
+ Disabled on: hanode1 (score:-INFINITY) (role: Master)
+
+
+# crm_simulate -sL|grep "promotion score"
+pgsqld:1 promotion score on hanode1: 1001
+pgsqld:2 promotion score on hanode3: 990
+pgsqld:0 promotion score on hanode2: -INFINITY
+~~~
+
+7. retirer les contraintes des commandes précédentes sur la ressource
+
+~~~console
+# pcs resource clear pgsqld-clone
+# crm_simulate -sL|grep "promotion score"
+pgsqld:2 promotion score on hanode1: 1001
+pgsqld:1 promotion score on hanode2: 1000
+pgsqld:0 promotion score on hanode3: 990
+~~~
+
+:::
+
+-----
+
+# Supervision
+
+Ce chapitre aborde les différents axes de supervision d'un cluster Pacemaker.
+
+-----
+
+## Sondes
+
+* supervision basique avec `crm_mon`
+* état du cluster avec `check_crm` (on pourrait ne pas remarquer les bascules!)
+ * [check_crm](https://exchange.nagios.org/directory/Plugins/Clustering-and-High-2DAvailability/Check-CRM/details)
+* état des __rings__ corosync avec `check_corosync_rings`
+ * [check_corosync_rings](https://exchange.nagios.org/directory/Plugins/Clustering-and-High-2DAvailability/Check-Corosync-Rings/details)
+
+::: notes
+
+Il existe peu de projet permettant d'intégrer la supervision d'un cluster
+Pacemaker au sein d'un système centralisé, eg. Nagios ou dérivés. Nous pouvons
+citer `crm_mon`, `check_crm` ou `check_corosync_rings`.
+
+**crm\_mon**
+
+L'outil `crm_mon` est capable de produire une sortie adaptée à Nagios grâce
+à l'argument `--simple-status`. Néanmoins, la remontée d'erreur est limitée
+à la seule disponibilité des nœuds, mais pas des ressources.
+
+Voici un exemple avec le cluster dans son état normal:
+
+~~~console
+# crm_mon --simple-status
+CLUSTER OK: 3 nodes online, 7 resources configured
+~~~
+
+L'outil ne rapporte pas d'erreur en cas d'incident sur une ressource:
+
+~~~console
+# killall postgres
+
+# pcs resource show
+ Master/Slave Set: pgsqld-clone [pgsqld]
+ pgsqld (ocf::heartbeat:pgsqlms): FAILED hanode1
+ Masters: [ hanode2 ]
+ Slaves: [ hanode3 ]
+ pgsql-master-ip (ocf::heartbeat:IPaddr2): Started hanode2
+
+# crm_mon --simple-status
+CLUSTER OK: 3 nodes online, 7 resources configured
+~~~
+
+Mais remonte une erreur en cas de perte d'un nœud:
+
+~~~console
+# pcs stonith fence hanode3
+Node: hanode3 fenced
+
+# crm_mon --simple-status
+CLUSTER WARN: offline node: hanode3
+~~~
+
+Cette sonde est donc peu utile, car souvent en doublon avec une sonde
+pré-existante confirmant que le serveur est bien démarré. Elle peut
+éventuellement servir à confirmer que les services Pacemaker/Corosync sont
+bien démarrés sur chaque nœud du cluster.
+
+
+**check\_crm**
+
+Malheureusement, l'outil n'a pas été mis à jour depuis 2013. Il dépend du
+paquet `libmonitoring-plugin-perl` sous Debian et dérivés et de `epel-release` et
+`perl-Monitoring-Plugin.noarch` sous les RedHat et dérivés.
+
+Le module perl ayant changé de nom depuis, il est nécessaire de modifier deux
+lignes dans le code source:
+
+~~~console
+sed -i 's/Nagios::Plugin/Monitoring::Plugin/' check_crm.pl
+~~~
+
+Ci-dessous, le cas d'une ressource ayant subit au moins une erreur. L'option -f
+permet d'indiquer le nombre minimal d'erreur avant que la sonde ne lève une
+alerte:
+
+~~~console
+# ./check_crm.pl
+check_crm WARNING - : pgsqld failure detected, fail-count=1
+
+# ./check_crm.pl -f 3
+check_crm OK - Cluster OK
+
+# pcs resource failcount reset pgsqld
+[...]
+
+# ./check_crm.pl
+check_crm OK - Cluster OK
+~~~
+
+L'argument `-c` de la sonde permet de lever une alerte si une
+contrainte existe sur une ressource suite à un déplacement forcé
+(eg. `crm_resource --ban`). Malheureusement, cette commande dépend de `crmsh`
+et ne fonctionne donc pas avec `pcs`.
+
+
+**check\_corosync\_rings**
+
+L'outil **check\_corosync\_rings** permet de détecter les incidents réseau
+au niveau Corosync. Par exemple, voici le cas d'un anneau défaillant :
+
+~~~console
+# ifdown eth1
+Device 'eth1' successfully disconnected.
+
+# ./check_corosync_ring.pl
+check_cororings CRITICAL - Running corosync-cfgtool failed
+
+# corosync-cfgtool -s
+Printing ring status.
+Local node ID 1
+RING ID 0
+ id = 192.168.122.2
+ status = ring 0 active with no faults
+RING ID 1
+ id = 192.168.100.2
+ status = Marking ringid 1 interface 192.168.100.2 FAULTY*
+
+# ifup eth1
+Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/3)
+
+# corosync-cfgtool -s
+Printing ring status.
+Local node ID 1
+RING ID 0
+ id = 192.168.122.2
+ status = ring 0 active with no faults
+RING ID 1
+ id = 192.168.100.2
+ status = ring 1 active with no faults
+
+# ./check_corosync_ring.pl
+check_cororings OK - ring 0 OK ring 1 OK
+~~~
+
+:::
+
+-----
+
+## Alertes Pacemaker
+
+* Déclenche une action en cas d'évènement
+* Possibilité d'exécuter un script
+* Exemples fournis : écriture dans un fichier de log, envoi de mail, envoi trap SNMP
+* Disponible depuis Pacemaker 1.1.15
+
+::: notes
+
+Depuis la version 1.1.15, Pacemaker offre la possibilité de lancer des
+[alertes](https://clusterlabs.org/pacemaker/doc/en-US/Pacemaker/1.1/html/Pacemaker_Explained/ch07.html)
+en fonction de certains évènements: nœud défaillant, ressource qui démarre
+ou s'arrête, etc.
+
+Le principe est assez simple, Pacemaker lance un script et lui transmet des
+variables d'environnement, un _timestamp_ et des destinataires (`recipient`).
+Cela laisse une grande liberté dans l'écriture de script.
+
+Pacemaker propose plusieurs scripts en exemple stockés dans
+`/usr/share/pacemaker/alerts` :
+
+ * `alert_file.sh.sample` : écriture de l'évènement dans un fichier texte
+ * `alert_smtp.sh.sample` : envoi d'un mail
+ * `alert_snmp.sh.sample` : envoi d'une "trap" snmp
+
+Voici un exemple de configuration avec `alert_file.sh.sample` :
+
+~~~xml
+
+
+
+
+
+
+
+
+
+
+~~~
+
+Dans cet exemple, Pacemaker exécutera le script
+`/usr/share/pacemaker/alerts/alert_file.sh` et lui transmet :
+
+ * `timestamp-format` : format du timestamp
+ * `logfile_destination` : défini comme un `recipient`, emplacement du fichier de destination
+
+Le script est appelé autant de fois que de `recipient` définis.
+
+Ci-après comment une telle alerte peut être déployée en utilisant les outils
+classiques. Bien entendu, une méthode plus intégrée et simple est proposée
+par l'outil `pcs`.
+
+~~~
+cp /usr/share/pacemaker/alerts/alert_file.sh.sample /usr/share/pacemaker/alerts/alert_file.sh
+chmod +x /usr/share/pacemaker/alerts/alert_file.sh
+touch /var/log/cluster/alerts.log
+chown hacluster:haclient /var/log/cluster/alerts.log
+crm_shadow --create alert
+cat < alert.xml
+
+
+
+
+
+
+
+
+
+
+EOF
+cibadmin --modify --xml-file alert.xml
+crm_shadow -d
+crm_shadow -f --commit alert
+~~~
+
+Dans les logs :
+
+~~~
+info: parse_notifications: We have an alerts section in the cib
+Found alert: id=alert_sample, path=[...]/alert_file.sh, timeout=30000, tstamp_format=%H:%M:%S.%06N
+Alert has recipient: id=logfile_destination, value=/var/log/cluster/alerts.log
+~~~
+
+Suite à un changement dans le cluster, nous observons dans le fichier
+`alerts.log` par exemple:
+
+~~~
+11:47:24.397811: Resource operation 'notify' for 'pgsqld' on 'hanode2': ok
+11:47:25.408174: Resource operation 'demote' for 'pgsqld' on 'hanode2': ok
+11:47:26.032790: Resource operation 'notify' for 'pgsqld' on 'hanode2': ok
+11:47:26.549325: Resource operation 'stop' for 'pgsql-master-ip' on 'hanode2': ok
+11:47:26.789720: Resource operation 'notify' for 'pgsqld' on 'hanode2': ok
+11:47:27.341088: Resource operation 'stop' for 'pgsqld' on 'hanode2': ok
+~~~
+
+Il pourrait être intéressant d'adapter ce script pour utiliser l'outil
+`logger` au lieu d'écrire directement dans un fichier. Ces modifications sont
+laissés à l'exercice du lecteur.
+
+:::
+
+-----
+
+### TP: Alertes Pacemaker
+
+::: notes
+
+1. installer `alert_file.sh.sample` dans `/var/lib/pacemaker/alert_file.sh` et
+ positionner son propriétaire et le droit d'exécution dessus.
+2. créer le fichier de log `/var/log/cluster/pcmk_alert.log`
+3. attribuer à ce fichier les mêmes droits et propriétaire que
+ `/var/log/cluster/corosync.log`
+4. créer une configuration `logrotate` pour ce fichier de log
+5. ajouter une alerte utilisant `alert_file.sh` avec `pcs`.
+ préciser le format de la date.
+6. ajouter `/var/log/cluster/pcmk_alert.log` comme destinataire de l'alerte
+7. vérifier avec `pcs` l'existence de votre alerte
+8. provoquer une bascule de `pgsqld-clone`
+9. comparer les log sur les trois nœuds
+
+:::
+
+-----
+
+### Correction: Alertes Pacemaker
+
+::: notes
+
+1. installer `alert_file.sh.sample` dans `/var/lib/pacemaker/alert_file.sh` et
+ positionner son propriétaire et le droit d'exécution dessus.
+
+Sur les trois nœuds du cluster:
+
+~~~console
+# install --owner=hacluster --group=haclient --mode=0755 \
+ /usr/share/pacemaker/alerts/alert_file.sh.sample \
+ /var/lib/pacemaker/alert_file.sh
+~~~
+
+2. créer le fichier de log `/var/log/cluster/pcmk_alert.log`
+
+Sur les trois nœuds du cluster:
+
+~~~console
+# touch /var/log/cluster/pcmk_alert.log
+~~~
+
+3. attribuer à ce fichier les mêmes droits et propriétaire que
+ `/var/log/cluster/corosync.log`
+
+Sur les trois nœuds du cluster:
+
+~~~console
+# chown hacluster:haclient /var/log/cluster/pcmk_alert.log
+# chmod 0660 /var/log/cluster/pcmk_alert.log
+~~~
+
+4. créer une configuration `logrotate` pour ce fichier de log
+
+Sur les trois nœuds du cluster:
+
+~~~console
+# cat <<'EOF' > /etc/logrotate.d/pcmk_alert
+/var/log/cluster/pcmk_alert.log {
+ missingok
+ compress
+ copytruncate
+ daily
+ rotate 31
+ minsize 2048
+ notifempty
+}
+EOF
+~~~
+
+5. ajouter une alerte utilisant `alert_file.sh` avec `pcs`
+
+~~~console
+# pcs alert create id=alert_file \
+ description="Log events to a file." \
+ path=/var/lib/pacemaker/alert_file.sh \
+ meta timestamp-format="%Y-%m-%d %H:%M:%S.%03N"
+~~~
+
+6. ajouter `/var/log/cluster/pcmk_alert.log` comme destinataire de l'alerte
+
+~~~console
+# pcs alert recipient add alert_file id=my-alert_logfile \
+ value=/var/log/cluster/pcmk_alert.log
+~~~
+
+7. vérifier avec `pcs` l'existence de votre alerte
+
+~~~console
+# pcs alert show
+Alerts:
+ Alert: alert_file (path=/var/lib/pacemaker/alert_file.sh)
+ Description: Log events to a file.
+ Recipients:
+ Recipient: my-alert_logfile (value=/var/log/cluster/pcmk_alert.log)
+~~~
+
+8. provoquer une bascule de `pgsqld-clone`
+
+~~~console
+# pcs resource move --master --wait pgsqld-clone hanode2
+# pcs resource clear pgsqld-clone
+~~~
+
+9. comparer les log sur les trois nœuds
+
+L'instance primary était sur `hanode1`. Nous trouvons dans ses log les
+opérations nécessaires pour déplacer le rôle `Master` ailleurs:
+
+~~~
+# cat /var/log/cluster/pcmk_alert.log
+16:09:40.796250: Resource operation 'notify' for 'pgsqld' on 'hanode1': ok
+16:09:41.437972: Resource operation 'demote' for 'pgsqld' on 'hanode1': ok
+16:09:41.666059: Resource operation 'notify' for 'pgsqld' on 'hanode1': ok
+16:09:42.159610: Resource operation 'stop' for 'pgsql-master-ip' on 'hanode1': ok
+16:09:42.415470: Resource operation 'notify' for 'pgsqld' on 'hanode1': ok
+16:09:43.396618: Resource operation 'notify' for 'pgsqld' on 'hanode1': ok
+16:09:43.611377: Resource operation 'monitor (16000)' for 'pgsqld' on 'hanode1': ok
+~~~
+
+L'instance cible était sur `hanode2`, nous trouvons dans ses log les
+opérations nécessaires à sa promotion:
+
+~~~
+# cat /var/log/cluster/pcmk_alert.log
+16:09:40.781285: Resource operation 'notify' for 'pgsqld' on 'hanode2': ok
+16:09:41.583250: Resource operation 'notify' for 'pgsqld' on 'hanode2': ok
+16:09:42.364046: Resource operation 'notify' for 'pgsqld' on 'hanode2': ok
+16:09:42.909637: Resource operation 'promote' for 'pgsqld' on 'hanode2': ok
+16:09:43.286059: Resource operation 'notify' for 'pgsqld' on 'hanode2': ok
+16:09:43.753243: Resource operation 'start' for 'pgsql-master-ip' on 'hanode2': ok
+16:09:44.013828: Resource operation 'monitor (10000)' for 'pgsql-master-ip' on 'hanode2': ok
+16:09:44.135493: Resource operation 'monitor (15000)' for 'pgsqld' on 'hanode2': master (target: 8)
+~~~
+
+Enfin, nous ne trouvons sur `hanode3` que les opérations de notification:
+
+~~~
+# cat /var/log/cluster/pcmk_alert.log
+16:09:40.824536: Resource operation 'notify' for 'pgsqld' on 'hanode3': ok
+16:09:41.654399: Resource operation 'notify' for 'pgsqld' on 'hanode3': ok
+16:09:42.201205: Resource operation 'notify' for 'pgsqld' on 'hanode3': ok
+16:09:43.413522: Resource operation 'notify' for 'pgsqld' on 'hanode3': ok
+~~~
+
+:::
+
diff --git a/docs/workshop/fr/workshop-PAF.md b/docs/workshop/fr/workshop-PAF.md
index 3d2e6ad..4882dc1 100644
--- a/docs/workshop/fr/workshop-PAF.md
+++ b/docs/workshop/fr/workshop-PAF.md
@@ -355,24 +355,19 @@ L'installation recommandée (et supportée) suivant les distributions de RHEL et
|:---------:|:--------:|:---------:|------------------------------|
| EL 7 | 2.x | 1.1.x | pcsd 0.9 |
| EL 8 | 3.x | 2.0.x | pcsd 0.10 |
-| Debian 8 | 1.4 | 1.1.x | crmsh |
-| Debian 9 | 2.4 | 1.1.x | pcs 0.9 ou crmsh 2.3 |
-| Debian 10 | 3.0 | 2.0.x | pcs 0.10 ou crmsh 4.0 |
-
-L'équipe de maintenance des paquets Pacemaker n'a pu intégrer les dernières
-versions des composants à temps pour la version 8 de Debian. Il a été décidé
-d'utiliser officiellement le dépôt backport de Debian pour distribuer ces
-paquets dans Debian 8. Les versions 8 et 9 de Debian partagent donc les mêmes
-versions des paquets concernant Pacemaker.
-
-L'initialisation du cluster avec `crmsh` 2.x n'est toujours pas fonctionnelle
-et ne devrait pas être corrigée, la branche 3.x étant désormais la branche
-principale du projet. La version 3.0 de `crmsh` supporte l'initialisation d'un
+| Debian 9 | 2.4 | 1.1.x | pcs 0.9 or crmsh 2.3 |
+| Debian 10 | 3.0 | 2.0.x | pcs 0.10 or crmsh 4.0 |
+| Debian 11 | 3.1 | 2.0.x | pcs 0.10 or crmsh 4.2 |
+
+Sous Debian 9, l'initialisation du cluster avec `crmsh` 2.x n'était toujours pas
+fonctionnelle. La version 3.0 de `crmsh` supportait l'initialisation d'un
cluster sous Debian mais avec un peu d'aide manuelle et quelques erreurs
-d'intégration.
+d'intégration. La branche principale du projet est désormais la 4.x, mais
+les auteurs de ce tutoriel ne l'ont pas encore testée.
-L'utilisation de `pcsd` et `pcs` est désormais pleinement fonctionne sous
-Debian. Voir à ce propos:
+Bien que `crmsh` soit l'outil d'administration historique sous les OS Debian et
+dérivés, l'utilisation de `pcsd` et `pcs` y est pleinement fonctionnel depuis
+la version 9 de Debian. Voir à ce propos:
:::
@@ -443,10 +438,10 @@ ces outils, ils sont très pratiques au quotidien et facilitent grandement la
gestion du cluster. De plus, ils intègrent toutes les bonnes pratiques
relatives aux commandes supportées.
-Tout au long de cette formation, nous utilisons le couple `pcs` afin de
-simplifier le déploiement et l'administration du cluster Pacemaker. Il est
-disponible sur la plupart des distributions Linux et se comportent de la même
-façon, notamment sur Debian et EL et leurs dérivés.
+Tout au long de cette formation, nous utilisons `pcs` afin de simplifier le
+déploiement et l'administration du cluster Pacemaker. Il est disponible sur la
+plupart des distributions Linux et se comportent de la même façon, notamment
+sur Debian et EL et leurs dérivés.
Ce paquet installe le CLI `pcs` et le daemon `pcsd`. Ce dernier s'occupe
seulement de propager les configurations et commandes sur tous les nœuds.
@@ -517,7 +512,7 @@ Pacemaker sont présents. Notamment:
::: notes
1. installer le paquet `pcs`
-2. activer le daemon `pcsd` au démarrage de l'instance et le démarrer
+2. activer le daemon `pcsd` au démarrage du serveur et le démarrer
:::
@@ -555,12 +550,12 @@ ou
* authentification des daemons `pcsd` entre eux
* création du cluster à l'aide de `pcs`
- crée la configuration corosync sur tous les serveurs
-* configuration de Pacemaker des _processus_ de Pacemaker
+* configuration des _processus_ de Pacemaker
::: notes
-La création du cluster se résume à créer le fichier de configuration de
-Corosync, puis à démarrer de Pacemaker.
+La création du cluster se résume à créer le même fichier de configuration de
+Corosync sur tous les nœuds, puis démarrer Pacemaker dessus.
L'utilisation de `pcs` nous permet de ne pas avoir à éditer la configuration de
Corosync manuellement. Néanmoins, un pré-requis à l'utilisation de `pcs` est
@@ -576,8 +571,9 @@ processus, pas la gestion du cluster. Notamment, où sont les journaux
applicatifs et leur contenu. Pour la famille des distributions EL, son
emplacement est `/etc/sysconfig/pacemaker`. Pour la famille des distributions
Debian, il sont emplacement est `/etc/default/pacemaker`. Ce fichier en
-concerne QUE l'instance locale de Pacemaker. Chaque instance peut avoir un
-paramétrage différent, mais cela est bien entendu déconseillé.
+concerne QUE l'instance locale de Pacemaker. Contrairement à Corosync, chaque
+instance Pacemaker peut avoir un paramétrage différent, mais cela est bien
+entendu déconseillé.
:::