Skip to content

Fix: sbd-cluster: periodically check connection to corosync-daemon - #76

Closed
wenningerk wants to merge 1 commit into
ClusterLabs:masterfrom
wenningerk:check_daemon_connection
Closed

Fix: sbd-cluster: periodically check connection to corosync-daemon#76
wenningerk wants to merge 1 commit into
ClusterLabs:masterfrom
wenningerk:check_daemon_connection

Conversation

@wenningerk

Copy link
Copy Markdown

No description provided.

@Splarv

Splarv commented Apr 18, 2019

Copy link
Copy Markdown

I think that here is more suitable place for discussion about this PR. :)

We just want to check the connection so extra checks of what is returned as nodeid are not necessary.

Any healthy check are not necessary, because all must work reasonably as is. :) But sometimes healthy checks checking some trivial. But no matter, I'll happy and without node id check.

But what about watchdog the healthy node. I have:

  • CentOS 7
  • pacemaker-1.1.19-8.el7_6.4.x86_64
  • corosync-2.4.3-4.el7.x86_64
  • sbd is taken from GitHub master with applied your patch.

When I do killall -s STOP corosync on one node, I get on this node:

Apr 18 16:59:19 tuchanka0a sbd[3826]: warning: inquisitor_child: Servant cluster is outdated (age: 4)
Apr 18 16:59:22 tuchanka0a sbd[3826]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)
Apr 18 16:59:22 tuchanka0a sbd[3826]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)

And the same on the second:

Apr 18 16:59:18 tuchanka0b cib[5711]: notice: Node tuchanka0a state is now lost
Apr 18 16:59:18 tuchanka0b cib[5711]: notice: Purged 1 peer with id=1 and/or uname=tuchanka0a from the membership cache
Apr 18 16:59:20 tuchanka0b kernel: sched: RT throttling activated
Apr 18 16:59:23 tuchanka0b sbd[5677]: warning: inquisitor_child: Servant cluster is outdated (age: 4)
Apr 18 16:59:26 tuchanka0b sbd[5677]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)

configs (-v -I 30 is wroten and commented by me, the default is without -v -I 30):
# cat /etc/sysconfig/sbd

# This file has been generated by pcs.
SBD_DELAY_START=no
SBD_OPTS="-v -n tuchanka0b"
#SBD_OPTS="-v -I 30 -n tuchanka0b"
SBD_PACEMAKER=yes
SBD_STARTMODE=always
SBD_WATCHDOG_DEV=/dev/watchdog
SBD_WATCHDOG_TIMEOUT=5

# cat /etc/corosync/corosync.conf

totem {
    version: 2
    cluster_name: krogan0
    secauth: off
    transport: udpu
}

nodelist {
    node {
        ring0_addr: tuchanka0a
        nodeid: 1
    }

    node {
        ring0_addr: tuchanka0b
        nodeid: 2
    }
}

quorum {
    provider: corosync_votequorum

    device {
        model: net
        votes: 1

        net {
            algorithm: ffsplit
            host: witness
        }
    }
}

logging {
    to_logfile: yes
    logfile: /var/log/cluster/corosync.log
    to_syslog: yes
}

@wenningerk
wenningerk force-pushed the check_daemon_connection branch from faad12d to d7a3c67 Compare April 18, 2019 14:30
@wenningerk

wenningerk commented Apr 18, 2019

Copy link
Copy Markdown
Author

Looks as if you are RT budgeting in your setup ('sched: RT throttling activated').
Maybe the budget for corosync is too small!?
Aah yes - if you are budgeting RT then probably SBD isn't running RT at all on your setup
which might explain one or the other thing.
Unfortunately there is no clean and generic possibility to deal with RT in these scenarios
from what systemd and the kernel are offering atm.
sbd and corosync are atm going different routes. sbd is just failing to set RT and corosync
is going a slightly hacky path that at least gives it RT within the limits of the root-slice.

@Splarv

Splarv commented Apr 18, 2019

Copy link
Copy Markdown

Looks as if you are RT budgeting in your setup ('sched: RT throttling activated').
Maybe the budget for corosync is too small!?

Say me how to check this. My setup is a default, I didn't change something so smart. I can only add that my test bed (correct? 🧐, the apple dictionary suggest such word) is on the VirtualBox under MacOs.

Unfortunately there is no clean and generic possibility to deal with RT in these scenarios
from what systemd and the kernel are offering atm.

As I said I'll be happy with just to add '-I 30' to my setup. The only reason why I mention all this, is that the HA system must work as expected with a default setup of a common user. To not to fix the same place twice. If you think that this problem is the only my special case, fine by me. I am looking forward for your patch in git.

@wenningerk

Copy link
Copy Markdown
Author

Do you get logs like "Unable to set scheduler priority to ..." from sbd.
What does 'cat /sys/fs/cgroup/cpu,cpuacct/cpu.rt_runtime_us',
'grep DefaultCPUAccounting /etc/systemd/system.conf' give you?
Do you have '/sys/fs/cgroup/cpu/system.slice'?
If you have you can try
'/usr/sbin/sysctl -n kernel.sched_rt_runtime_us > /sys/fs/cgroup/cpu/system.slice/cpu.rt_runtime_us'
before cluster startup.

@kgaillot kgaillot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of minor comments

Comment thread src/sbd-cluster.c
#endif
/* TODO - Make a CPG call and only call notify_parent() when we get a reply */
notify_parent();
break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be unreachable code if SUPPORT_COROSYNC && CHECK_CPG_HANDLE is true but HAVE_DECL_PCMK_CLUSTER_CMAN is false -- I'd just separate the corosync and cman blocks

Comment thread src/sbd-cluster.c
so going ahead with whatever found in
cluster.cpg_handle should be safe
*/
if (cpg_local_get(cluster.cpg_handle, &local_nodeid) == CS_OK) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CPG doesn't need to be connected (cluster_connect_cpg()) before calling cpg_local_get()?

cluster will be initialized to all 0's because it's static, so I don't think there will be any randomness. Which is good because otherwise static analysis might complain about using uninitialized memory :)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs the connection but that code is on pacemaker-side in crm_cluster_connect.
Question is if it wouldn't be cleaner to have something like crm_cluster_check in pacemaker doing basically cpg_local_get or whatever seems to be useful for the cluster-type.

Initially there is gonna be a 0 but 0 is as well a valid cpg_handle. So checking for 0 isn't safe.
Haven't run coverity over it but using static-memory shouldn't result in complaints I guess.
The randomness comes from corosync which adds a random number to the cpg_handle.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, makes sense now :)

@Splarv

Splarv commented Apr 22, 2019

Copy link
Copy Markdown

Do you get logs like "Unable to set scheduler priority to ..." from sbd.

# grep 'Unable to set scheduler priority to' /var/log/messages
nope

What does 'cat /sys/fs/cgroup/cpu,cpuacct/cpu.rt_runtime_us',

# cat /sys/fs/cgroup/cpu,cpuacct/cpu.rt_runtime_us
950000

'grep DefaultCPUAccounting /etc/systemd/system.conf' give you?

# grep DefaultCPUAccounting /etc/systemd/system.conf
#DefaultCPUAccounting=no

Do you have '/sys/fs/cgroup/cpu/system.slice'?

# cat /sys/fs/cgroup/cpu/system.slice
cat: /sys/fs/cgroup/cpu/system.slice: No such file or directory

I stopped corosync on one node (killall -s STOP corosync) and I attached logs from the other "healthy" node.
First log with sbd -v, the healthy node was watchdoged.
default.log.gz

Second, sbd -v -I 30, all worked as expected.
30.log.gz

@wenningerk

wenningerk commented Apr 22, 2019

Copy link
Copy Markdown
Author

Ok that looks if CPUAccounting isn't enabled. Good so far for rt-scheduling ;-)
Sorry for not asking the most obvious: Are corosync & sbd rt-scheduled (e.g. with top)?
There is one more scheduling-parameter interesting here: /proc/sys/kernel/sched_rt_period_us (should be 1000000us)
And have you checked for other rt-scheduled processes (other than corosync & sbd) that could have eaten up the time or if you can see which processes are running wild? (maybe top is sufficient before you go into ltt-ng and alike ...)
This is bare-metal, no VMs of and kind!? And not running hot so that the CPU is throttling ...

@Splarv

Splarv commented Apr 22, 2019

Copy link
Copy Markdown

Ok that looks if CPUAccounting isn't enabled. Good so far for rt-scheduling ;-)

Don't sure that the problem is in RT-scheduling. I see the time problem is roughly 20 seconds, don't sure that this is due to scheduling.

Sorry for not asking the most obvious: Are corosync & sbd rt-scheduled (e.g. with top)?

From top, default sort:

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
 3739 root      rt   0  130584  52828  14608 S  0,7  7,0   0:52.31 sbd
 3748 root      rt   0  223140 124876  95656 S  0,3 16,5   0:59.38 corosync
 3779 haclust+  20   0  111200  17800  10604 S  0,3  2,4   0:14.57 cib

There is one more scheduling-parameter interesting here: /proc/sys/kernel/sched_rt_period_us (should be 1000000us)

# cat /proc/sys/kernel/sched_rt_period_us
1000000

And have you checked for other rt-scheduled processes (other than corosync & sbd) that could have eaten up the time or if you can see which processes are running wild? (maybe top is sufficient before you go into ltt-ng and alike ...)

Top, sorted by PR (all PR rt):

    7 root      rt   0    0,0m   0,0m   0,0m S  0,0  0,0   0:00.00 migration/0
   11 root      rt   0    0,0m   0,0m   0,0m S  0,0  0,0   0:00.09 watchdog/0
 3737 root      rt   0   88,6m  12,7m  11,2m S  0,0  1,7   0:00.62 sbd
 3739 root      rt   0  127,5m  51,6m  14,3m S  0,3  7,0   0:53.92 sbd
 3740 root      rt   0  105,5m  28,8m  23,3m S  0,0  3,9   0:01.98 sbd
 3748 root      rt   0  217,9m 121,9m  93,4m S  0,3 16,5   1:00.59 corosync

This is bare-metal, no VMs of and kind!? And not running hot so that the CPU is throttling ...

As I said this is a "test bed" (a correct word? :)) MacBook Pro with installed VirtualBox. Testing VMs, that forms a Pacemaker cluster, are under VirtualBox.

@wenningerk

Copy link
Copy Markdown
Author

If your test environment is VMs in VirtualBox on a MacBook Pro I guess you have to expect certain timings needed to be relaxed.
I don't have personal experience with exactly that environment. But desktop-hypervisors in general heavily depend on scheduling of the host-os. I guess you on top heavily over-commit your hypervisor. Guess VirtualBox doesn't have an interface to tell the guest-kernel when the VM has been preempted due to over-commitment. So when being preempted during an rt-process running the kernel is gonna account the whole time while the VM had been preempted to rt-scheduling. That describes why RT throttling is triggered worsening the situation.
So what you are probably experiencing is that the VM you stopped corosync is being rebooted so that the other VM is being preempted for large chunks of time triggering RT throttling so that corosync and sbd are scheduled even less time than the whole VM is.
Are you using a watchdog inside the VMs? If yes it is probably softdog that unfortunately doesn't support poweroff instead of rebooting. So what happens if you don't use softdog but instead configure SBD_TIMEOUT_ACTION (kind of new feature) to be 'off,noflush'? (Should make the VM just halt instead of using vast amounts of CPU to reboot.)

@Splarv

Splarv commented Apr 24, 2019

Copy link
Copy Markdown

I don't have personal experience with exactly that environment. But desktop-hypervisors in general heavily depend on scheduling of the host-os. I guess you on top heavily over-commit your hypervisor.

Don't think so. Every VM consume only one virtual CPU kernel, while CPU has 12 physical kernels.

Are you using a watchdog inside the VMs? If yes it is probably softdog that unfortunately doesn't support poweroff instead of rebooting. So what happens if you don't use softdog but instead configure SBD_TIMEOUT_ACTION (kind of new feature) to be 'off,noflush'? (Should make the VM just halt instead of using vast amounts of CPU to reboot.)

Just power off (hardly, from VirtualBox manager) one of the VM. The second VM was watchdoged.

@wenningerk

wenningerk commented Apr 24, 2019

Copy link
Copy Markdown
Author

I don't have personal experience with exactly that environment. But desktop-hypervisors in general heavily depend on scheduling of the host-os. I guess you on top heavily over-commit your hypervisor.

Don't think so. Every VM consume only one virtual CPU kernel, while CPU has 12 physical kernels.

Well, maybe tight on some other resource and blocking scheduling of the virtual CPU ... as said desktop-hypervisors are not necessarily made to separate virtual workloads as the ones made for running loads in datacenters (KVM, ESX, XEN, ...)

Are you using a watchdog inside the VMs? If yes it is probably softdog that unfortunately doesn't support poweroff instead of rebooting. So what happens if you don't use softdog but instead configure SBD_TIMEOUT_ACTION (kind of new feature) to be 'off,noflush'? (Should make the VM just halt instead of using vast amounts of CPU to reboot.)

Just power off (hardly, from VirtualBox manager) one of the VM. The second VM was watchdoged.

??? Don't get it ...
Wanted to know if you have set SBD_WATCHDOG_DEV to /dev/watchdog or something. If yes is there softdog behind /dev/watchdog?
Do you mean instead of letting the VM boot through you issued a hard poweroff in VirtualBox manager when you saw that it would start to reboot? And the 2nd machine still rebooted? As said try VMs with 2 virtual cores.

@Splarv

Splarv commented Apr 24, 2019

Copy link
Copy Markdown

Wanted to know if you have set SBD_WATCHDOG_DEV to /dev/watchdog or something.

Yes

# cat /etc/sysconfig/sbd
# This file has been generated by pcs.
SBD_DELAY_START=no
SBD_OPTS="-v -n tuchanka0a"
#SBD_OPTS="-v -I 30 -n tuchanka0a"
SBD_PACEMAKER=yes
SBD_STARTMODE=always
SBD_WATCHDOG_DEV=/dev/watchdog
SBD_WATCHDOG_TIMEOUT=5

If yes is there softdog behind /dev/watchdog?

Yes

# lsmod |grep softdog
softdog                13319  1

But I don't think that the reason is in a watchdog. The real reason is (from the healthy node):

Apr 24 14:59:20 tuchanka0b sbd[3754]: warning: inquisitor_child: Servant cluster is outdated (age: 4)
Apr 24 14:59:23 tuchanka0b sbd[3754]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)

Do you mean instead of letting the VM boot through you issued a hard poweroff in VirtualBox manager when you saw that it would start to reboot? And the 2nd machine still rebooted?

Nope. I didn't stop corosync in this time. I started a normal cluster with two healthy nodes and hardly power off one of them from VirtualBox manager. The other one was rebooted with the last message in /var/log/messages as typed above.

As said try VMs with 2 virtual cores.

Why not? Btw, I am not sure that the cores is virtual, because max number on cores (12) in the interface is equal to the number of hardware cores of CPU.

With 2 cores for each two nodes the result is same. I powered off hardly the one healthy node and the other was rebooted:

Apr 24 16:33:11 tuchanka0b stonith-ng[3811]:  notice: Watchdog will be used via SBD if fencing is required
Apr 24 16:33:34 tuchanka0b corosync[3779]: [TOTEM ] A processor failed, forming new configuration.
Apr 24 16:33:36 tuchanka0b corosync[3779]: [TOTEM ] A new membership (192.168.89.2:632) was formed. Members left: 1
Apr 24 16:33:36 tuchanka0b corosync[3779]: [TOTEM ] Failed to receive the leave message. failed: 1
Apr 24 16:33:36 tuchanka0b corosync[3779]: [VOTEQ ] waiting for quorum device Qdevice poll (but maximum for 30000 ms)
Apr 24 16:33:36 tuchanka0b stonith-ng[3811]:  notice: Node tuchanka0a state is now lost
Apr 24 16:33:36 tuchanka0b stonith-ng[3811]:  notice: Purged 1 peer with id=1 and/or uname=tuchanka0a from the membership cache
Apr 24 16:33:36 tuchanka0b attrd[3813]:  notice: Node tuchanka0a state is now lost
Apr 24 16:33:36 tuchanka0b attrd[3813]:  notice: Removing all tuchanka0a attributes for peer loss
Apr 24 16:33:36 tuchanka0b attrd[3813]:  notice: Purged 1 peer with id=1 and/or uname=tuchanka0a from the membership cache
Apr 24 16:33:36 tuchanka0b cib[3810]:  notice: Node tuchanka0a state is now lost
Apr 24 16:33:36 tuchanka0b cib[3810]:  notice: Purged 1 peer with id=1 and/or uname=tuchanka0a from the membership cache
Apr 24 16:33:36 tuchanka0b crmd[3815]:  notice: Our peer on the DC (tuchanka0a) is dead
Apr 24 16:33:36 tuchanka0b crmd[3815]:  notice: State transition S_NOT_DC -> S_ELECTION
Apr 24 16:33:39 tuchanka0b sbd[3767]: warning: inquisitor_child: Servant cluster is outdated (age: 4)
Apr 24 16:33:42 tuchanka0b sbd[3767]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)
Apr 24 16:33:42 tuchanka0b sbd[3767]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)
packet_write_wait: Connection to 192.168.89.2 port 22: Broken pipe

@wenningerk

Copy link
Copy Markdown
Author

But I don't think that the reason is in a watchdog. The real reason is (from the healthy node):

Apr 24 14:59:20 tuchanka0b sbd[3754]: warning: inquisitor_child: Servant cluster is outdated (age: 4)
Apr 24 14:59:23 tuchanka0b sbd[3754]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)

Just wanted to explain a way so that you don't get a node immediately rebooting after the timeout-issue is detected (meaning on the node where you stopped corosync).
But as you are getting the effect as well when you are doing a hard poweroff of the node we don't need that 'trick'.
But I anyway guess that what we see is somehow 'works as designed'.
You probably had that behavior (2nd node rebooting if you turn off the 1st) already before the corosync-observation-patch!?!
Let me explain:
1st - pure watchdog-fencing without a shared disk isn't supported on a 2-node-cluster as you require 'real quorum' for the principle to work.
So if you are running a 2-node-cluster this is detected (quorum gotten from corosync via pacemaker will persist even if one node goes away) and quorum gotten from pacemaker is kind of ignored and the number of participants to the cpg-protocol > 1 is used instead.
This of course just makes sense if you are using a shared disk on top. Node stays online then if it either sees the disk or the peer so that none of both becomes a spof. Or explained a little different 2 out of 3 entities have to be available (node1/node2/disk).

If you add a 3rd node to your cluster corosync-observation should work fine and the reboot of the node observed (or hard-shutdown) shouldn't tear down any peer-nodes.

@Splarv

Splarv commented Apr 24, 2019

Copy link
Copy Markdown

But I don't think that the reason is in a watchdog. The real reason is (from the healthy node):

Apr 24 14:59:20 tuchanka0b sbd[3754]: warning: inquisitor_child: Servant cluster is outdated (age: 4)
Apr 24 14:59:23 tuchanka0b sbd[3754]: warning: inquisitor_child: Latency: No liveness for 4 s exceeds threshold of 3 s (healthy servants: 0)

Just wanted to explain a way so that you don't get a node immediately rebooting after the timeout-issue is detected (meaning on the node where you stopped corosync).

Nope, after I stopped corosync, the right node is rebooted. There is all fine.

But as you are getting the effect as well when you are doing a hard poweroff of the node we don't need that 'trick'.

Not "But", but "And". :) And we need that trick, because if the sbd is documented as a watchdog daemon, it must works as a watchdog daemon correctly. And all worked with option -I 30 and this is fine for my task.

May be the problem, as I see in last log is:

Apr 24 16:33:36 tuchanka0b crmd[3815]:  notice: Our peer on the DC (tuchanka0a) is dead
Apr 24 16:33:36 tuchanka0b crmd[3815]:  notice: State transition S_NOT_DC -> S_ELECTION
Apr 24 16:33:39 tuchanka0b sbd[3767]: warning: inquisitor_child: Servant cluster is outdated (age: 4)

May be the problem is when corosync is in the state "ELECTION" it stops answering for a time.

But I anyway guess that what we see is somehow 'works as designed'.
You probably had that behavior (2nd node rebooting if you turn off the 1st) already before the corosync-observation-patch!?!

Nope.

Let me explain:
1st - pure watchdog-fencing without a shared disk isn't supported on a 2-node-cluster as you require 'real quorum' for the principle to work.

This is not my case. I don't have a 2-node-cluster, I have a 2-node-cluster-with-quorum-device and a 'real quorum' with 3 votes.

@Splarv

Splarv commented Apr 24, 2019

Copy link
Copy Markdown

To make this patch working with default timeouts, the default timeouts must be changed. Don't think that will be good to change timeouts of the corosync. IMHO will be better change timeouts in the sbd-inquisitor.c:574:

            if (age < (int)(timeout_io+timeout_loop)) {

The real timeout is the sum of the timeout_io (changed by -I option) and the timeout_loop (-3 option).

Default timeout_loop is defined in sbd-common.c:44

int     timeout_loop            = 1;

And I think this will be better not touch.

Default timeout_io is in sbd-common.c:45:

int     timeout_io      = 3;

So only need to change to

int     timeout_io      = 30;

Also need to change the man page. This is a full patch:
patch.diff.gz
Now all worked fine, with or power off or stoping corosync.

@wenningerk

wenningerk commented Apr 24, 2019

Copy link
Copy Markdown
Author

I don't think it is a good idea that we try to cover up the symptoms instead of trying to find the reason.
Your node is triggering rt-trottling - meaning you either have some kind of preemption of the VM or some rt-process is really hogging your CPU(s) for at least 1s. That is definitely bad and there are other things that can't live with such a behavior. In my setup I definitely don't get the behavior you described.
People - digimer for instance - are already complaining that clusters using sbd aren't reactive enough ...

@Splarv

Splarv commented Apr 25, 2019

Copy link
Copy Markdown

I don't think it is a good idea that we try to cover up the symptoms instead of trying to find the reason.

Okey, I like your desire to fix the reason and I'll help as I can.

Your node is triggering rt-trottling -

Absolutely not. There is not any rt-trottling after I set 2 core per node. But problem still exists.

meaning you either have some kind of preemption of the VM or some rt-process is really hogging your CPU(s) for at least 1s.

Nope. To achieve such result there must be 4s lag. But the lag is even more. Let me show you. I slightly change code of sbd-cluster.c in such way:

        cl_log(LOG_INFO, "Before cpg_local_get()");
        if (cpg_local_get(cluster.cpg_handle, &local_nodeid) == CS_OK) {
            cl_log(LOG_INFO, "After true cpg_local_get()");
            notify_parent();
        } else
            cl_log(LOG_INFO, "After false cpg_local_get()");

And so:

Apr 25 14:39:56 tuchanka0b sbd[3838]:   cluster:     info: notify_timer_cb: Before cpg_local_get()
Apr 25 14:40:23 tuchanka0b sbd[3838]:   cluster:     info: notify_timer_cb: After true cpg_local_get()

There is 27 seconds lag in the cpg_local_get(). Here is the full log.
messages.log.gz

In my setup I definitely don't get the behavior you described.

This is very interesting. I don't know your setup. May be the matter in the new version of the corosync, CentOS 7 and RedHat 7 has very old soft. I'll try to compile a new version.

PS I can compile corosync 3.0.1 and 2.99.5 on centos7, but I can't install. :) Well, no matter. As I said I like your patch as it is.

@wenningerk

wenningerk commented Apr 25, 2019

Copy link
Copy Markdown
Author

PS I can compile corosync 3.0.1 and 2.99.5 on centos7, but I can't install. :) Well, no matter. As I said I like your patch as it is.

Well I don't like it that much if it behaves like that on older corosync-versions ;-)
Guess I'll have a look on corosync 2.4.x myself ...

ps: are you on clusterlabs-irc? just handier for chat ...

pps: it seems that the reason of the difference in behavior of our setups isn't the corosync-version but rather use of qdevice :-(

@Splarv

Splarv commented Apr 25, 2019

Copy link
Copy Markdown

PS I can compile corosync 3.0.1 and 2.99.5 on centos7, but I can't install. :) Well, no matter. As I said I like your patch as it is.

Well I don't like it that much if it behaves like that on older corosync-versions ;-)
Guess I'll have a look on corosync 2.4.x myself ...

Why not? This can be described in the dependences or manual to set with old version of corosync option -I 30.

@wenningerk

Copy link
Copy Markdown
Author

Why not? This can be described in the dependences or manual to set with old version of corosync option -I 30.

That reduces responsiveness of the cluster by a factor of something like 5 or so.
And I simply can't release a fix doing that.

@jfriesse

Copy link
Copy Markdown
Member

Main problem is because (for whatever reason) qdevice didn't provided ACK/NACK till watchdog was triggered - following line in the log is important:

Apr 24 16:33:36 tuchanka0b corosync[3779]: [VOTEQ ] waiting for quorum device Qdevice poll (but maximum for 30000 ms)

@Splarv Do you have an idea why qdevice decision takes too long (it shouldn't)? Some kind of slow heuristics? Something obvious in qdevice log?

@wenningerk

Copy link
Copy Markdown
Author

Main problem is because (for whatever reason) qdevice didn't provided ACK/NACK till watchdog was triggered

Bottom-line seems to be that the patch in here seems to be the right thing to do.
It just fixes another issue as well that we didn't have on the radar so far.
qdevice delays update of quorate-state here as well and sbd needs that to be
updated within the sbd-timeout.
Maybe some sanity-checking of the configuration done by sbd here would be
helpful. But that is definitely a separate fix.

@Splarv

Splarv commented Apr 25, 2019

Copy link
Copy Markdown

Main problem is because (for whatever reason) qdevice didn't provided ACK/NACK till watchdog was triggered

Looked like a light at the end of a dark tunnel.

@Splarv Do you have an idea why qdevice decision takes too long (it shouldn't)? Some kind of slow heuristics? Something obvious in qdevice log?

Okey, about qdevice. It is in the third VM with CentOS 7.

# rpm -q corosync-qnetd
corosync-qnetd-2.4.3-4.el7.x86_64
# rpm -q corosync
corosync-2.4.3-4.el7.x86_64

Was installed by pcs qdevice setup model net --enable --start

# pcs qdevice status net --full
QNetd address:			*:5403
TLS:				Supported (client certificate required)
Connected clients:		2
Connected clusters:		1
Maximum send/receive size:	32768/32768 bytes
Cluster "krogan0":
    Algorithm:		Fifty-Fifty split
    Tie-breaker:	Node with lowest node ID
    Node ID 2:
        Client address:		::ffff:192.168.89.2:50028
        HB interval:		8000ms
        Configured node list:	1, 2
        Ring ID:		1.2cc
        Membership node list:	1, 2
        Heuristics:		Undefined (membership: Undefined, regular: Undefined)
        TLS active:		Yes (client certificate verified)
        Vote:			ACK (ACK)
    Node ID 1:
        Client address:		::ffff:192.168.89.1:41980
        HB interval:		8000ms
        Configured node list:	1, 2
        Ring ID:		1.2cc
        Membership node list:	1, 2
        Heuristics:		Undefined (membership: Undefined, regular: Undefined)
        TLS active:		Yes (client certificate verified)
        Vote:			No change (ACK)

On the working node was configured by
pcs quorum device add model net host='witness' algorithm=ffsplit

# pcs quorum device status --full
Qdevice information
-------------------
Model:			Net
Node ID:		2
HB interval:		10000ms
Sync HB interval:	30000ms
Configured node list:
    0	Node ID = 1
    1	Node ID = 2
Heuristics:		Disabled
Ring ID:		1.2cc
Membership node list:	1, 2
Quorate:		Yes
Quorum node list:
    0	Node ID = 1, State = member
    1	Node ID = 2, State = member
Expected votes:		3
Last poll call:		2019-04-25T18:01:50 (cast vote)

Qdevice-net information
----------------------
Cluster name:		krogan0
QNetd host:		witness:5403
Connect timeout:	8000ms
HB interval:		8000ms
VQ vote timer interval:	5000ms
TLS:			Supported
Algorithm:		Fifty-Fifty split
Tie-breaker:		Node with lowest node ID
Poll timer running:	Yes (cast vote)
State:			Connected
TLS active:		Yes (client certificate sent)
Connected since:	2019-04-25T14:38:31
Echo reply received:	2019-04-25T18:01:50

config on Witness VM

# cat /etc/sysconfig/corosync-qnetd
# Corosync Qdevice Network daemon init script configuration file

# COROSYNC_QNETD_OPTIONS specifies options passed to corosync-qnetd command
# (default is no options).
# See "man corosync-qnetd" for detailed descriptions of the options.
COROSYNC_QNETD_OPTIONS=""

# COROSYNC_QNETD_RUNAS specifies user under which qnetd daemon should be running
# (not set or empty is default and means "user who executes init script")
# Make sure to set correct owner of directories /etc/corosync/qnetd and
# /var/run/corosync-qnetd
# This has no effect if systemd unit is used (you have to change unit file)
COROSYNC_QNETD_RUNAS=""

Qdevice logs (I added -dd to the COROSYNC_QNETD_OPTIONS):

Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug   Client ::ffff:192.168.89.2:50684 (cluster krogan0, node_id 2) sent membership node list.
Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug     msg seq num = 16
Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug     ring id = (2.2d0)
Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug     heuristics = Undefined
Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug     node list:
Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug       node_id = 2, data_center_id = 0, node_state = not set
Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug   ffsplit: Membership for cluster krogan0 is not yet stable
Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug   Algorithm result vote is Wait for reply
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 warning Client ::ffff:192.168.89.1:42006 doesn't sent any message during 20000ms. Disconnecting
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   Client ::ffff:192.168.89.1:42006 (init_received 1, cluster krogan0, node_id 1) disconnect
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   ffsplit: Membership for cluster krogan0 is now stable
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   ffsplit: Quorate partition selected
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug     node list:
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug       node_id = 2, data_center_id = 0, node_state = not set
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   ffsplit: No client gets NACK
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   Sending vote info to client ::ffff:192.168.89.2:50684 (cluster krogan0, node_id 2)
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug     msg seq num = 3
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug     vote = ACK
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   Client ::ffff:192.168.89.2:50684 (cluster krogan0, node_id 2) replied back to vote info message
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug     msg seq num = 3
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   ffsplit: All ACK votes sent for cluster krogan0
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   Client ::ffff:192.168.89.2:50684 (cluster krogan0, node_id 2) sent quorum node list.
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug     msg seq num = 17
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug     quorate = 1
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug     node list:
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug       node_id = 1, data_center_id = 0, node_state = dead
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug       node_id = 2, data_center_id = 0, node_state = member
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   Algorithm result vote is No change

@jfriesse

jfriesse commented Apr 25, 2019

Copy link
Copy Markdown
Member

@Splarv Thank you for super detailed logs! I was able to reproduce the scenario and now I finally fully understand what is happening, but I'm not entirely decided if it is bug or what we can do with that other than changing timeouts/document recommended timeouts (ether sbd or qdevice/qnetd). So what is happening:

  • Node1 and 2 are both running corosync and corosync-qdevice which is happily connected to node 3, where qnetd is running
  • Corosync on node 1 is paused
  • corosync-qdevice on node 1 cannot receive or sent any messages from corosync and because it is not doing any kind of healthcheck of corosync connection it will block
  • Corosync on node 2 eventually finds out that node 1 is not communicating and starts creating membership. Because qdevice is active on node 2, it will wait for maximum 30 seconds for qdevice reply and blocks.
  • Qdevice on node 2 asks qnetd on node 3 for vote. Qnetd on node 3 expects that both node 1 and 2 are alive, so it instruct qdevice on node 2 to wait for vote a while (till node 1 don't send its membership view - what (as we know) is not going to happen (but qnetd doesn't know it yet)).
  • Qnetd has ability to detect dead peers. This detection is executed every dpd_interval and by default is set to 10 seconds. If peer doesn't send any message during configured 2 * heartbeat (0.8 * quorum.device.timeout = 8 second) then peer is marked as failed and disconnected. 2 * 8 sec = 16 sec and because dpd is happening every 10 second -> real timeout is 20 second.
  • So after 20 seconds Qnetd finds out that Node 1 qdevice didn't sent any message and disconnects it
  • Right after that Qnetd finds out that only active node in cluster is Node 2 and it can send final vote
  • Node 2 qdevice finally gets qnetd ACK (NACK would work same way) so it can call votequorum_qdevice_poll what results in unblocking of the corosync

So ~20 second timeout for sbd should be enough when used with qdevice (and for this IMHO kind of artificial, problem).

@jfriesse

jfriesse commented Apr 26, 2019

Copy link
Copy Markdown
Member

It would be bug if qdevice would block forever. This is not the case. Corosync would proceed after sync_timeout (default 30s) no matter if qdevice calls votequorum_qdevice_poll or not. And also qnetd detects death of one of the nodes so it will eventually make a progress.
Also keep in mind that corosync must block till qdevice makes qualified decision otherwise it would work with outdated information -> providing outdated information to clients (pacemaker/sbd/...).

In such case corosync for whole 30 seconds don't answer for any question, even for question about local nodeid. :) It's frozen.

It's frozen for clients, yes

But the watchdog timeout 5 seconds and the watchdog daemon ask corosync every 1 second for prove of live. I don't know what is timeout for detection live from other nodes, or corosync answers them?

Depends on token timeout. Default is 1000 + (number_of_nodes - 2) * 650.

IMHO, instead in such situation the corosync must answer something like 'quorum unknown' (yep, I am DB programer :). As for me, it's like PostgreSQL stops answer for all query just because one of fields become null.

It's not only about quorum (so one field). It's about sending/receiving cpg, quorum, cmap, cfg, ... This is more like if your db client would loose connection to sql server and db connector would return "random" (or unknown) values instead of waiting for TCP timeout - possible but not super useful. + It would break EVS what is just no no no (it's like if your psql would break ACID).

Also there si a way how to check livenes even of corosync being in sync phase (calling votequorum) , but it actually doesn't help too much and only makes problem to appear later.

Apr 25 18:11:57 witness corosync-qnetd: Apr 25 18:11:57 debug   Client ::ffff:192.168.89.2:50684 (cluster krogan0, node_id 2) sent membership node list. <--- Qnetd got info about changed membership from node 2
...
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 warning Client ::ffff:192.168.89.1:42006 doesn't sent any message during 20000ms. Disconnecting <--- Qnetd find out Node 1 is dead
...
Apr 25 18:12:14 witness corosync-qnetd: Apr 25 18:12:14 debug   Client ::ffff:192.168.89.2:50684 (cluster krogan0, node_id 2) replied back to vote info message <-- Qdevice on node 2 got ACK

so 18:11:57 - 18:12:14 = 17 seconds.
Of course if you count in corosync token loss detection and sbd sampling interval then it may be slightly more.

Eh, you mean only qnetd timeout, I see. I said that 30 seconds must be timeout_io in sbd (option -I 30).

Anyway, I will think about it a little more deeper but for now I see only solution in reducing the timeouts (especially dead peer detection on qnetd side).

Well, reducing timeout for qnetd is fine by me. Qnetd now gives 30 seconds reaction in case of node power off, while in case of PostgreSQL fault, the PostgreSQL in monitored every 15 seconds by default, so qnetd's timeouts looked like slightly large. On other side 30 seconds is small enough time for a user will not make a call to a support team. :)

Well, after this qnetd will freeze the corosync for 15 seconds instead of 30 seconds, for instance. But sbd still will expect that corosync answers every 1 second. And after 3 seconds (timeout_io by default) it will rise alarm and reboot node. And watchdog expect sbd reaction at least every 5 seconds. That's why I think thats freeze corosync is incorrect.

Would you sacrifice ACID?

@Splarv

Splarv commented Apr 26, 2019

Copy link
Copy Markdown

@Splarv Would you mind to test following changes and share if behavior is as expected?

In corosync.conf, add

...
    device {
        model: net
        votes: 1

        sync_timeout: 3000
        timeout: 1000

....
}

and on qnetd side change /etc/sysconfig/corosync-qnetd line where COROSYNC_QNETD_OPTIONS is set to

COROSYNC_QNETD_OPTIONS="-S dpd_interval=1000"

Nice enough. I saw only 1-2 second lag between Before cpg_local_get() and After true cpg_local_get(). I tried with the default timeout_io in sbd (3 seconds), the node with stopped corosync was rebooted in 3 seconds, while the healthy node raised masters and continue working without visible problems.

Depends on token timeout. Default is 1000 + (number_of_nodes - 2) * 650.

So for two nodes it will be... just 1 second. So remote nodes get a prove of life in 1 second, but local node got own the nodeid from the own corosync for 30 seconds (in worst case). Yep, as variant may be to change a way, how the local node gets a prove of life from the own corosync (do the same way, as do remote node).

But with new timeouts for qnetd and qdevice all looking fine with default timeout_io of sbd.

But what will be maximum theoretical lag for cpg_local_get()? If it will be 3 seconds (thus equal timeout_io of sbd) it is still dangerous becase it with small probability still will be able to suddenly reboot the last healthy node.

I saw 3 seconds. May be need 4 to watchdog the last healthy node. It's unsafe, one 1 seconds lag and.... Is it depend on sync_timeout: of qdevice? I changed it to 2000. According to the manual:

sync_timeout
Specifies how often corosync-qdevice should call the votequorum_poll function during a
sync phase. It is recommended that you don't change this value. Default is 30000.

May be even 1000 will be better here?

@wenningerk

Copy link
Copy Markdown
Author

So for two nodes it will be... just 1 second. So remote nodes get a prove of life in 1 second, but local node got own the nodeid from the own corosync for 30 seconds (in worst case). Yep, as variant may be to change a way, how the local node gets a prove of life from the own corosync (do the same way, as do remote node).

As already stated above a delay of the time needed to get the quorum-state updated in here is exactly what we need. If we can't assume that quorum-state-updates come within the timeout we can't assume that a separated node is gonna suicide within this timeout. Consequence would be pacemaker introducing a split-brain.
Of course we could check the liveness of the local corosync-instance by other means but having learned about how things are different with qdevice that would mean that we had to introduce another way of verification that quorum-updates are coming in quick enough. But I guess for now what we get with the patch in this PR should be good enough. Of course there is some ugliness behind checking quorum-related issues both in pacemaker & cluster-watcher (but that is already the case since the overriding pacemaker-quorum by cpg-counting in case of 2-node-flag set).

Atm I see issues with setting the qdevice-defaults that low as pcs doesn't support setting them up for one of the probably most used scenarios for qdevice (2 sites running services and a 3rd site - kind of poorly connected - as arbiter).
On the other hand - as stated above - I'm hesitant setting the sbd-defaults up so that they work with the current qdevice-defaults as it makes clusters not using qdevice more sluggish as they had to be. (And we have a switch in behavior due to an update.)
Of course upstream we can do whatever we want but when it comes to distros we need sync with high-level-tooling.

@Splarv

Splarv commented Apr 26, 2019

Copy link
Copy Markdown

Atm I see issues with setting the qdevice-defaults that low as pcs doesn't support setting them up for one of the probably most used scenarios for qdevice (2 sites running services and a 3rd site - kind of poorly connected - as arbiter).

As I can understand from the man corosync-qdevice the sync_timeout, we are talking about, is not a real timeout, but a rate, how often called votequorum_poll function. As already @jfriesse said, normal behaviour for remote nodes is 1 second, so I don't see a reason to prevent qdevice call votequorum_poll function every second.

Also, timeouts 10s and 30s looked like qnetd was developed in the time of the phone modem internet. It will be not bad, if we move timeouts to the modern reality.

@Splarv

Splarv commented Apr 26, 2019

Copy link
Copy Markdown

And one more cent that the prove of life of the corosync must be slightly different. When I type ifdown eth0 the node is not watchdoged. In the log I see only:

Apr 26 16:57:13 tuchanka0a corosync[3824]: [MAIN  ] Totem is unable to form a cluster bec
ause of an operating system or network fault (reason: totem is continuously in gather sta
te). The most common cause of this message is that the local firewall is configured impro
perly.

Cib is not updated, the pacemaker show that the all fine, the PostgreSQL keep works in master mode (on both nodes: on the faulted old and is rised on healthy). In such situation the fault node must be watchdoged, as it will happens with working fencing.

Afaik that is an issue with corosync 2.x and should be fixed in 3.x.
@jfriesse: anything useful we can do here on corosync 2.x?

@jfriesse

jfriesse commented Apr 29, 2019

Copy link
Copy Markdown
Member

@Splarv Thank you for the confirmation of working reduced timeouts.

10-30sec is not that much for "phone modem internet" (even that doesn't have such lags :) ) but mostly for heuristics which must also fit into this limit - and heuristics can be almost everything - including access to half-dead NFS server, ... Also we are talking about EVS so time itself (in theory) doesn't play any role (in practice it is quite opposite).

Anyway, 10-30 sec is probably too much and when I was thinking about the problem little deeper I think it should be (by-default, it should stay fully configurable to whatever value one need) based on the token-timeout rather than some fixed value (like sync_timeout = 3*token_timeout)

@wenningerk Could you please elaborate how you find out that "If we can't assume that quorum-state-updates come within the timeout we can't assume that a separated node is gonna suicide within this timeout."? Quorum-state-update will come within timeout (30 second is worst case with default config) and keep in mind all other nodes are blocked so there will be no split-brain - all nodes will wait for end of sync phase. "... verification that quorum-updates are coming in quick enough" - same question, why you need them in some time, when everything is synchronous (all nodes will block)? So why not to call votequorum (which has exception and calls proceed even in sync phase)?

@Splarv ifdown example is extremely nice example of why I keep saying that sbd without poison pill is kind of "broken by design" (or more mildly said - "fragile by design"). It's other nodes responsibility to shut down dead node. And there is really not too much we can do about it. This concrete issue is fixed upstream by corosync/corosync@96354fb, but more generally it is still issue, because whenever corosync stops cooperating - and this is what fencing is trying to solve - sbd should take action and I don't believe it is possible without sbd having other channel to get relevant info.

@wenningerk

Copy link
Copy Markdown
Author

10-30sec is not that much for "phone modem internet" (even that doesn't have such lags :) ) but mostly for heuristics which must also fit into this limit - and heuristics can be almost everything - including access to half-dead NFS server, ... Also we are talking about EVS so time itself (in theory) doesn't play any role (in practice it is quite opposite).

I agree that the average roundtrip is never that much but WAN connections have hickups of a couple of seconds allowed in their contracts afaik.

Anyway, 10-30 sec is probably too much and when I was thinking about the problem little deeper I think it should be (by-default, it should stay fully configurable to whatever value one need) based on the token-timeout rather than some fixed value (like sync_timeout = 3*token_timeout)

Making it a multiple of token_timeout is a good idea I guess. There is anyway no sense in having a low token_timeout if quorum-updates are possibly delayed by way longer timeouts.

@wenningerk Could you please elaborate how you find out that "If we can't assume that quorum-state-updates come within the timeout we can't assume that a separated node is gonna suicide within this timeout."? Quorum-state-update will come within timeout (30 second is worst case with default config) and keep in mind all other nodes are blocked so there will be no split-brain - all nodes will wait for end of sync phase. "... verification that quorum-updates are coming in quick enough" - same question, why you need them in some time, when everything is synchronous (all nodes will block)? So why not to call votequorum (which has exception and calls proceed even in sync phase)?

Wanted to state that it doesn't make sense here to require the corosync-test to return earlier than the maximum delay we have for quorum-state-updates.
The fact that everything is blocked and it thus wouldn't be problematic if fencing would be delayed is definitely a good point. But it probably requires still some thinking. What happens if fenced on the DC acks a node to be fenced and the DC then decides to locally take over a resource. Would that be frozen as well?

@Splarv ifdown example is extremely nice example of why I keep saying that sbd without poison pill is kind of "broken by design". It's other nodes responsibility to shut down dead node. And there is really not too much we can do about it. This concrete issue is fixed upstream by corosync/corosync@96354fb, but more generally it is still issue, because whenever corosync stops cooperating - and this is what fencing is trying to solve - sbd should take action and I don't believe it is possible without sbd having other channel to get relevant info.

Well it burns down to basic dealing with watchdogs. Have a small, easy to verify loop that triggers a hardware watchdog while it does heartbeating to other instances. Other instances have to adopt that principle in a way that either the mechanism used as heartbeating is gonna fail or they are operational with a very high probability - potentially breaking their own functionality again up according to a similar principle.
Btw. unless you disable cluster & pacemaker - watcher even adding a shared disk won't get you rid of relying to the cluster-software in some form. Otherwise you'd have to have 3 shared disks and everyone has to have access to at least 2 of them not to make the disk a spof. And still you have to rely in the software (how simple that might be) that is checking for disk-accessibility to be bound into the watchdog-loop properly.
Everything that doesn't actively answer 'I've killed node-x successfully' is some sort of sacrifice - but in turn offers more flexibility and use-cases not possible otherwise.

@jfriesse

Copy link
Copy Markdown
Member

10-30sec is not that much for "phone modem internet" (even that doesn't have such lags :) ) but mostly for heuristics which must also fit into this limit - and heuristics can be almost everything - including access to half-dead NFS server, ... Also we are talking about EVS so time itself (in theory) doesn't play any role (in practice it is quite opposite).

I agree that the average roundtrip is never that much but WAN connections have hickups of a couple of seconds allowed in their contracts afaik.

Anyway, 10-30 sec is probably too much and when I was thinking about the problem little deeper I think it should be (by-default, it should stay fully configurable to whatever value one need) based on the token-timeout rather than some fixed value (like sync_timeout = 3*token_timeout)

Making it a multiple of token_timeout is a good idea I guess. There is anyway no sense in having a low token_timeout if quorum-updates are possibly delayed by way longer timeouts.

Yep, I believe we are totally on same page in this respect. If somebody has a super slow wan then probably want a larger token timeout. If only qnetd is on super slow wan then they can set timeouts to whatever fits, but I believe 99.99% of use cases will work better with smaller timeouts. I will prepare some patch (hopefully soon).

Said that it may make sense for sbd to also use such timeout (maybe 2 * sync_timeout?) so users become free of unexpected "surprise".

@wenningerk Could you please elaborate how you find out that "If we can't assume that quorum-state-updates come within the timeout we can't assume that a separated node is gonna suicide within this timeout."? Quorum-state-update will come within timeout (30 second is worst case with default config) and keep in mind all other nodes are blocked so there will be no split-brain - all nodes will wait for end of sync phase. "... verification that quorum-updates are coming in quick enough" - same question, why you need them in some time, when everything is synchronous (all nodes will block)? So why not to call votequorum (which has exception and calls proceed even in sync phase)?

Wanted to state that it doesn't make sense here to require the corosync-test to return earlier than the maximum delay we have for quorum-state-updates.
The fact that everything is blocked and it thus wouldn't be problematic if fencing would be delayed is definitely a good point. But it probably requires still some thinking. What happens if fenced on the DC acks a node to be fenced and the DC then decides to locally take over a resource. Would that be frozen as well?

This is really pacemaker question, because when corosync unblocks (and all nodes unblocks in virtually same moment) it will inform both pacemaker and sbd and at least this message should proceed without any blocking.

@Splarv ifdown example is extremely nice example of why I keep saying that sbd without poison pill is kind of "broken by design". It's other nodes responsibility to shut down dead node. And there is really not too much we can do about it. This concrete issue is fixed upstream by corosync/corosync@96354fb, but more generally it is still issue, because whenever corosync stops cooperating - and this is what fencing is trying to solve - sbd should take action and I don't believe it is possible without sbd having other channel to get relevant info.

Well it burns down to basic dealing with watchdogs. Have a small, easy to verify loop that triggers a hardware watchdog while it does heartbeating to other instances. Other instances have to adopt that principle in a way that either the mechanism used as heartbeating is gonna fail or they are operational with a very high probability - potentially breaking their own functionality again up according to a similar principle.

Honestly I can imagine corosync to feed "watchdog" daemon (call it sbd/systemd-watchdogd/...) and such solution may be more reliable because we would remove "sampling" problem.

But this still doesn't solve main problem. At least in corosync node itself never marks itself as dead. That is why I believe other nodes has to.

Btw. unless you disable cluster & pacemaker - watcher even adding a shared disk won't get you rid of relying to the cluster-software in some form. Otherwise you'd have to have 3 shared disks and everyone has to have access to at least 2 of them not to make the disk a spof. And still you have to rely in the software (how simple that might be) that is checking for disk-accessibility to be bound into the watchdog-loop properly.
Everything that doesn't actively answer 'I've killed node-x successfully' is some sort of sacrifice - but in turn offers more flexibility and use-cases not possible otherwise.

I know it is trade-of. But were you thinking about some kind of network poison pill? To really prevent situations when corosync becomes non-cooperative?

@wenningerk

Copy link
Copy Markdown
Author

Said that it may make sense for sbd to also use such timeout (maybe 2 * sync_timeout?) so users become free of unexpected "surprise".

There is some kind of chicken-and-egg issue here due to startup and stuff.
But I guess extending the already existant checks in pacemaker (currently just match between watchdog-timeout and stonith-watchdog-timeout-property) might make sense. That part anyway has to be touched since Ken has introduced the automatic deriving of stonith-watchdog-timeout (till then stonith-watchdog-timeout was global and every node checked against the locally configured watchdog-timeout and if not configured properly refused pacemaker-startup - when they now derive it themselves every node comes up and silently assumes other nodes are configured the same way - very dangerous).

Honestly I can imagine corosync to feed "watchdog" daemon (call it sbd/systemd-watchdogd/...) and such solution may be more reliable because we would remove "sampling" problem.

That takes us to a lack of a watchdog-model being usable by multiple instances.
systemd offers something but would at least require some overhaul as atm it kicks the watchdog in an internal loop that it does iirc 50 times making it quite unusable for having a guaranteed time after which a node is reset (assume 5s as minium watchdog time to be sure it is properly triggered in the usual loops * 50 = way too long).
But if you send some heartbeat via the corosync-api I can use that in sbd. Were talking about that using the status-api iirc but would like to rather have something a little bit more light-weight and designed for that (guess corosync isn't expecting to kill the node atm if it is late on delivering status).

I know it is trade-of. But were you thinking about some kind of network poison pill? To really prevent situations when corosync becomes non-cooperative?

Didn't think of much but network poison pill might be something to think of (depending on what one might see behind it ;-) ). Just wanted to deprive you from the idea that everything would be safe and sane in the poison-pill (on disk) case ;-)

@Splarv

Splarv commented Apr 29, 2019

Copy link
Copy Markdown

(like sync_timeout = 3*token_timeout)

@jfriesse, can you explain "why?" such formulae. Or point me where I can read about it.

So why not to call votequorum (which has exception and calls proceed even in sync phase)?

May be solution is to call votequorum, but check not that a quorum is quorable, but only that the return is without errors?

@Splarv ifdown example is extremely nice example of why I keep saying that sbd without poison pill is kind of "broken by design" (or more mildly said - "fragile by design"). It's other nodes responsibility to shut down dead node.

As I said there is situation when cluster is on different datacentres. And we try to solve the problems are concerned when one of DC is isolated or blackouted.

And there is really not too much we can do about it. This concrete issue is fixed upstream by [corosync/corosync@96354fb]

@jfriesse Thank you, you saved my time. Now I know that this is fixed in at least v2.99.3 (real commit is 96b4bd1).

but more generally it is still issue, because whenever corosync stops cooperating - and this is what fencing is trying to solve - sbd should take action and I don't believe it is possible without sbd having other channel to get relevant info.

Why not? Why sbd can not do what fencing do?

@jfriesse

Copy link
Copy Markdown
Member

(like sync_timeout = 3*token_timeout)

@jfriesse, can you explain "why?" such formulae. Or point me where I can read about it.

I don't fully understand your question. If question is why it is larger than token timeout then idea is simple. Corosync changes membership because of something happened (node dead/switch dead/...) and it should give a qdevice/qnetd slightly more time to get all the heuristics done, possible slower connection to qnetd/...

If it is other why then please be more specific what 'why' you mean.

So why not to call votequorum (which has exception and calls proceed even in sync phase)?

May be solution is to call votequorum, but check not that a quorum is quorable, but only that the return is without errors?

Sure, this is why I've suggested votequorum_getinfo to Klaus. That call can be used instead of current cpg call.

@Splarv ifdown example is extremely nice example of why I keep saying that sbd without poison pill is kind of "broken by design" (or more mildly said - "fragile by design"). It's other nodes responsibility to shut down dead node.

As I said there is situation when cluster is on different datacentres. And we try to solve the problems are concerned when one of DC is isolated or blackouted.

And there is really not too much we can do about it. This concrete issue is fixed upstream by [corosync/corosync@96354fb]

@jfriesse Thank you, you saved my time. Now I know that this is fixed in at least v2.99.3 (real commit is 96b4bd1).

2.99.3 is pre-release of corosync which you probably do not want to use. Use 3.0.1, 2.4.4 or if you want not yet released version use camelback or needle branch.

but more generally it is still issue, because whenever corosync stops cooperating - and this is what fencing is trying to solve - sbd should take action and I don't believe it is possible without sbd having other channel to get relevant info.

Why not? Why sbd can not do what fencing do?

I was talking about sbd without shared disk. That relies on Corosync/pacemaker being cooperative, what may not be always true (for various reasons, bugs included). As I've told X times during the thread, corosync never marks itself as dead. And also as Klaus described, everything what doesn't ack 'I've killed node-x successfully' is sort of sacrifice.

@Splarv

Splarv commented Apr 29, 2019

Copy link
Copy Markdown

If it is other why then please be more specific what 'why' you mean.

Yep, why is bigger and why is bigger in 3 times. :) But not two, for instance.

Sure, this is why I've suggested votequorum_getinfo to Klaus. That call can be used instead of current cpg call.

Thanks for explanation. I am not so good in english and understanding of internal processes of pacemaker/corosync/etc to always understand what are you talking about. %(

2.99.3 is pre-release of corosync which you probably do not want to use. Use 3.0.1, 2.4.4 or if you want not yet released version use camelback or needle branch.

I thought about v2.99.5, because v3.0.1. need even more dependences, for instance libknet, which is absent in CentOS 7. While 2.4.4 don't have this commit. Okey, I'll keep in mind to use 3.0.1 instead of 2.99.5.

Why not? Why sbd can not do what fencing do?
I was talking about sbd without shared disk. That relies on Corosync/pacemaker being cooperative, what may not be always true (for various reasons, bugs included). As I've told X times during the thread, corosync never marks itself as dead. And also as Klaus described, everything what doesn't ack 'I've killed node-x successfully' is sort of sacrifice.

As I understand you correctly, you talk about acknowledge 'I've killed node-x successfully'. In case of isolated sbd and watchdog this is not necessary, we just trust a watchdog. And this is not necessary because after successful watchdog, nobody will be to ask such acknowledge. :)

Eh, may be you incorrectly understood me.

Why not? Why sbd can not do what fencing do?

I mean only test for 'proof of life'. In case of fencing the remote node somehow get 'proof of live' from the other node and get decision to fence in case of the corosync or the pacemaker (don't know exactly who) of some node stop respond. Why sbd can't get the 'proof of life' in the exactly the same way?

@jfriesse

jfriesse commented Apr 29, 2019

Copy link
Copy Markdown
Member

If it is other why then please be more specific what 'why' you mean.

Yep, why is bigger and why is bigger in 3 times. :) But not two, for instance.

Can be. I mean, setting default timeouts is not exactly exact science. It's more like "I feel this may work". But does it mean it will fit everybody ? I would say "no way", but we must try to find something what is good for most of the people. And of course everything should be configurable so (this bug is nice example) you don't need to wait till I make a patch for qnetd/corosync/qdevice but you can just set whatever you need.

Sure, this is why I've suggested votequorum_getinfo to Klaus. That call can be used instead of current cpg call.

Thanks for explanation. I am not so good in english and understanding of internal processes of pacemaker/corosync/etc to always understand what are you talking about. %(

Yep, no worries.

2.99.3 is pre-release of corosync which you probably do not want to use. Use 3.0.1, 2.4.4 or if you want not yet released version use camelback or needle branch.

I thought about v2.99.5, because v3.0.1. need even more dependences, for instance libknet, which is absent in CentOS 7. While 2.4.4 don't have this commit. Okey, I'll keep in mind to use 3.0.1 instead of 2.99.5.

Few comments:

Why not? Why sbd can not do what fencing do?
I was talking about sbd without shared disk. That relies on Corosync/pacemaker being cooperative, what may not be always true (for various reasons, bugs included). As I've told X times during the thread, corosync never marks itself as dead. And also as Klaus described, everything what doesn't ack 'I've killed node-x successfully' is sort of sacrifice.

As I understand you correctly, you talk about acknowledge 'I've killed node-x successfully'. In case of isolated sbd and watchdog this is not necessary, we just trust a watchdog. And this is not necessary because after successful watchdog, nobody will be to ask such acknowledge. :)

Other nodes will ask..

Edit: Ok, They will not, but it's just because of stonith-watchdog-timeout and node belief that sbd did its job.

Eh, may be you incorrectly understood me.

Why not? Why sbd can not do what fencing do?

I mean only test for 'prove of life'. In case of fencing the remote node somehow get 'prove of live' from the other node and get decision to fence in case of the corosync or the pacemaker (don't know exactly who) of some node stop respond. Why sbd can't get the prove of life in the exactly the same way?

I'm not entirely sure if you don't see it other way around. Also I'm not entirely sure how exactly sbd works (edit: studied it little more so now I can understand how sbd works), but with standard power fencing it works following way:

  • let's say we have 3 nodes and node 1 stops responding
  • corosync does it's job and finds out node 1 is dead informing cpg clients (pcmk) on Nodes 2 and 3 about this fact
  • pcmk finds out that it is quorate so it should fence dead node
  • pcmk calls fence agent
  • Fence agent turns off power source, wait till power source is really off (trust hw that it behaves correctly), turn on power source, wait till power source is on

SBD has no way for last step. There is nobody who can say that node was really turned off.

edit: This is why sbd without disk needs stonith-watchdog-timeout.

@wenningerk Correct me if I'm totally wrong.

@Splarv

Splarv commented Apr 29, 2019

Copy link
Copy Markdown

@jfriesse Okey, my question was not philosophical. Let's return to your timeouts. You suggest token_timeout=1s, sync_timeout=3s. I see drawback of sync_timeout=3s, because it is equal to the default timeout_io in sbd and can occasionally fire a reboot by the inquisitor checking of servants. Can you point me is there will be obvious drawback of using token_timeout=1s, sync_timeout=2s (I didn't see) or token_timeout=1s, sync_timeout=1s? And with your timeouts the cluster reacts in ten times faster in the poweroff node case and I like this in any way.

  • Also this bug seems to be serious enough so I plan to release 2.4.5 just right after fixing this bug

I look forward to it.

I'm not entirely sure if you don't see it other way around. Also I'm not entirely sure how exactly sbd works, but with standard power fencing it works following way:

  • let's say we have 3 nodes and node 1 stops responding
  • corosync does it's job and finds out node 1 is dead informing cpg clients (pcmk) on Nodes 2 and 3 about this fact

I see your point: this do corosync, but we may not rely on local corosync to test local corosync. My question was how corosync tests other corosync? Does it send a special kind of package? Request? But I think now, that this check may be too complex to realise it outside corosync to check local corosync.

  • pcmk finds out that it is quorate so it should fence dead node
  • pcmk calls fence agent
  • Fence agent turns off power source, wait till power source is really off (trust hw that it ibehaves correctly), turn on power source, wait till power source is on

SBD has no way for last step. There is nobody who can say that node was really turned off.

Yes. SBD use a watchdog/softdog and a default watchdog action, which is a hardware reset, usually. Or (or may be not 'or', but 'and') it use SysRq sequences, as I understand. Yep, relying on a watchdog is a risk, a watchdog can fail. But this is acceptable risk, a watchdog usually reliable enough and this is common to trust to it. So stonith-watchdog-timeout property is acceptable for sure, IMHO.

@jfriesse

Copy link
Copy Markdown
Member

@jfriesse Okey, my question was not philosophical. Let's return to your timeouts. You suggest token_timeout=1s, sync_timeout=3s. I see drawback of sync_timeout=3s, because it is equal to the default timeout_io in sbd and can occasionally fire a reboot by the inquisitor checking of servants. Can you point me is there will be obvious drawback of using token_timeout=1s, sync_timeout=2s (I didn't see) or token_timeout=1s, sync_timeout=1s? And with your timeouts the cluster reacts in ten times faster in

I've tried to explain it in comment #76 (comment) . Also I'm kind of expecting sbd will also adjust default timeout based on token timeout.

the poweroff node case and I like this in any way.

  • Also this bug seems to be serious enough so I plan to release 2.4.5 just right after fixing this bug

I look forward to it.

I'm not entirely sure if you don't see it other way around. Also I'm not entirely sure how exactly sbd works, but with standard power fencing it works following way:

  • let's say we have 3 nodes and node 1 stops responding
  • corosync does it's job and finds out node 1 is dead informing cpg clients (pcmk) on Nodes 2 and 3 about this fact

I see your point: this do corosync, but we may not rely on local corosync to test local corosync. My question was how corosync tests other corosync? Does it send a special kind of package? Request?

Very high level, corosync uses token ring to detect failures and order messages. For more info, you can check https://github.com/corosync/corosync/wiki/Developers#reference-documentation

But I think now, that this check may be too complex to realise it outside corosync to check local corosync.

  • pcmk finds out that it is quorate so it should fence dead node
  • pcmk calls fence agent
  • Fence agent turns off power source, wait till power source is really off (trust hw that it ibehaves correctly), turn on power source, wait till power source is on

SBD has no way for last step. There is nobody who can say that node was really turned off.

Yes. SBD use a watchdog/softdog and a default watchdog action, which is a hardware reset, usually. Or (or may be not 'or', but 'and') it use SysRq sequences, as I understand. Yep, relying on a watchdog is a risk, a watchdog can fail. But this is acceptable risk, a watchdog usually reliable enough and this is common to trust to it. So stonith-watchdog-timeout property is acceptable for sure, IMHO.

@Splarv

Splarv commented Apr 30, 2019

Copy link
Copy Markdown

I've tried to explain it in comment [#76 (comment)]

Heh, I see slightly more time. :)

Well, I tried investigate by myself. As I can understand there is a token_timeout, which used by totem to detect a fault node, equals to roughly 1s. Can be slightly more time for more nodes. And there are analogous timeouts in qdevice (quorum.device.timeout and quorum.device.sync_timeout), which also used to detect a fault node, but they are ten times greater: 10s and 30s (by default). They are used in chain: qnetd->qdevice->corosync. I didn't look on the direction to qnetd. Between qdevice and corosync all is looked rather simple, time to time qdevice send signals to corosync that the qnetd is online by calling votequorum_qdevice_poll(). quorum.device.timeout and quorum.device.sync_timeout have similar sense, but one of them used in normal workflow, other in the sync phase. And this timeouts used in the corosync and in the qdevice. In the corosync this parameters used as timeout, in which the corosync expect signals from qdevice. And in qdevice they used in parameter heartbeat_interval=0.8*timeout, perhaps used as time interval for such signals.

Well, you said that the sync_timeout must be slightly more time, because sync phase is a critical situation, when pacemaker and corosync do something, may be some heuristics (which is off by default) and a server has increased load. But modern servers are quick enough for pacemaker loads and so, as I see, there may be does not need additional time in sync phase. 1s may be sufficient. I checked, it works for me even on my 'slow' VMs.

Very high level, corosync uses token ring to detect failures and order messages. For more info, you can check https://github.com/corosync/corosync/wiki/Developers#reference-documentation

Thanks for point me to the right direction. The documentation was useless, I looked into the source.

I am interesting in totem_get_stats() and in returned structure totem_stats_t.hdr.last_updated. As I understand this is constantly updated timestamp by the totem and so, perhaps, it can be used as a heartbeat of totem and so corosync. Heh, I'll have long holidays now, shall try after that.

@jfriesse

jfriesse commented May 2, 2019

Copy link
Copy Markdown
Member

@Splarv Honestly it looks like you are grasping the problem only from your perspective of two node cluster (probably not super overloaded). I'm grasping the problem from wider perspective, where 2 node cluster is super popular, but some customers demands 32 nodes (and timeout there is really not 1sec). Perspective when sometimes machines are so overloaded that corosync is not scheduled for 3+ seconds. So I think 3 * token_timeout is going to be good default value. If you think that 1 s will fit your deployment better you have possibility to change timeouts in config.

@wenningerk

Copy link
Copy Markdown
Author

I guess the main risk in using a watchdog isn't the reliability of the watchdog itself. That should be sufficiently high.
Main thing is to have a health-check that is reliable enough both regarding detection of situations where something isn't working as being able to detect these situations within reliable time-frames so that we have a reliable timeout we can set on the other nodes to proceed after.
This is why I'm not immediately jumping on votequorum as I'm seeing the current behavior (using cpg_local_get) rather like a feature - at least as long I'm not convinced that everything within pacemaker would really be blocked while sync is happening. I know corosync-messaging is blocked but I'm not sure what happens when local APIs are used. Btw. even if everything is blocked to prevent split-brain I don't see a real drawback in setting watchdog-timeouts accordingly.
Talking of the 3s - this is just the time after which sbd is gonna spit out warnings before it does the reset after 5s (using current defaults). But of course we are having cascading timeouts here so that it is probably not very safe having one of these as high as 3s.

@jfriesse

jfriesse commented May 2, 2019

Copy link
Copy Markdown
Member

@wenningerk I believe you are still considering setting default timeout based on token timeout, are you? Because otherwise no matter what I will set as a default we get into problems with higher number of nodes (14 nodes = default timeout 10.1s).

Also it's not 3s. Keep in mind that timeout starts on both other nodes and qnetd side, so real timeout is actually sync_timeout - token_timeout = 2s (for two node cluster).

@wenningerk

wenningerk commented May 2, 2019

Copy link
Copy Markdown
Author

@jfriesse: atm approach is that pacemaker checks if stonith-watchdog-timeout is compatible with (bigger) than watchdog-timeout configured with sbd. On a node where this isn't fulfilled pacemaker isn't gonna come up and start resources and thus there isn't gonna be any problem with that node not rebooting quickly enough.
As this behavior is safe but unhandy we meanwhile have this half-baked feature that when you set stonith-watchdog-timeout=-1 it is derived automatically from what is configured with sbd. So every node will basically have it's own timeout matching it's own sbd-timeout. Problem with that is that the timeout being used by watchdog-fencing would have to match the sbd-timeout configured on the node to be fenced and not the own node. Thus we either need a per target-node watchdog-timeout for pacemaker or the timeout being used by pacemaker has to match the largest sbd-timeout in the cluster. (With a feature making it possible to enable/disable-watchdog-fencing for certain target-nodes on the way this per target-node-value sounds like the right way to go.)
Unfortunately corosync isn't the only instance that defines sbd-timeout. shared-disk and basic possibility which values can be set on the hardware-watchdog are input to that considerations as well.
To have a consistent approach it probably makes sense to be able to set sbd-timeout = -1 (the default then at some point in time) as well for being derived automatically from corosync-timing.
As corosync and sbd are coming up simultaneously there is of course still the chicken-and-egg issue I did address earlier in the thread.
First step could then be to at least add an additional check into pacemaker as to assure that the timeout being used for watchdog-fencing isn't too short for corosync as to prevent split-brain.
In a next step we could make sbd suicide immediately if corosync-timing doesn't match watchdog-timeout configured with sbd (better would be failing startup but I'm not sure if we know early enough ....).
With the latter implemented I could probably use votequorum without loosing much (but probably wouldn't have to as cpg_local_get should never timeout).

@jfriesse

jfriesse commented May 3, 2019

Copy link
Copy Markdown
Member

@wenningerk Ok, I believe we are on same page. "largest sbd-timeout in the cluster" seems (IMHO) as a best and most reliable way. I'm not entirely sure if corosync and sbd should be coming up simultaneously, but if it should then what about having some "default" timeout which will be used until better (defined by corosync/shared-disk/....) is available?

Anyway. I was thinking about all consequences of timeout running on both qnetd side and other nodes side and I believe sbd will work even without changing its defaults for large clusters, because when other nodes finally find out that victim node is dead, qnetd will already know it. So reply will be instant (with exception of slow heuristics).

@Splarv

Splarv commented May 13, 2019

Copy link
Copy Markdown

@jfriesse,

@Splarv Honestly it looks like you are grasping the problem only from your perspective of two node cluster (probably not super overloaded). I'm grasping the problem from wider perspective, where 2 node cluster is super popular, but some customers demands 32 nodes (and timeout there is really not 1sec).

Well, I think that the default configuration must be for most popular cases and unexperienced users, but not for very rare cases with very professional admins. :) But no matter, I see that @wenningerk exactly said my point about 3s.

But of course we are having cascading timeouts here so that it is probably not very safe

And you already discussed about this somehow. Now I can confirm that I was understood. :)

@Splarv

Splarv commented May 20, 2019

Copy link
Copy Markdown

Okey, comrades. I need your advise and may be help. I tried, but I don't see easy way to get totem_stats_t.hdr.last_updated in the sbd. But looked like I can use for a heartbeat the orf_token_rx from the cmap. It constantly increased in the working node, but on an node isolated by ifdown eth0 it stoped. And so there can be simple logic to compare orf_token_rx on every loop in sbd and notify_parent() only if orf_token_rx was changed.

The first question: "Will this be correct?"

And say the truth it will be not easy for me. As I see there is already exist some logic for cmap, for instance to connect to the cmap service, but only in the conditional compilation directives CHECK_TWO_NODE. And so it is hard for me to change the code with keeping in mind all caveats of conditional compilation, which I don't know.

@jfriesse

Copy link
Copy Markdown
Member

I don't think so, because cmap call is blocked during sync phase same way as cpg is (for same good reason) - or maybe I don't understand the idea (I have exactly zero experience with sbd code).

@Splarv

Splarv commented May 20, 2019

Copy link
Copy Markdown

I don't think so, because cmap call is blocked during sync phase same way as cpg is (for same good reason) - or maybe I don't understand the idea (I have exactly zero experience with sbd code).

Yep, it's not bad, may be, with right timeouts. The reason of my idea is to make not a trivial check but check the health of corosync. It may help in cases when corosync looked like working, but don't work indeed. For instance, in the case of ifdown eth0.

@Splarv

Splarv commented Aug 9, 2019

Copy link
Copy Markdown

Perhaps after PR#83 is accepted, this PR may be closed.

@wenningerk

Copy link
Copy Markdown
Author

Perhaps after PR#83 is accepted, this PR may be closed.

I've opened https://bugzilla.redhat.com/show_bug.cgi?id=1703128 to not loose track of the more sophisticated checking.

@wenningerk wenningerk closed this Sep 17, 2019
Splarv pushed a commit to domclick/tuchanka that referenced this pull request Aug 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants