]>
Commit | Line | Data |
---|---|---|
cbca2c55 DM |
1 | package PVE::HA::NodeStatus; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use Data::Dumper; | |
7 | ||
8 | sub new { | |
c79442f2 | 9 | my ($this, $haenv, $status) = @_; |
cbca2c55 DM |
10 | |
11 | my $class = ref($this) || $this; | |
12 | ||
13 | my $self = bless { | |
c79442f2 | 14 | haenv => $haenv, |
c0bbd038 | 15 | status => $status, |
5385a606 | 16 | last_online => {}, |
cbca2c55 DM |
17 | }, $class; |
18 | ||
19 | return $self; | |
20 | } | |
21 | ||
22 | # possible node state: | |
b9e715a1 | 23 | my $valid_node_states = { |
c0bbd038 DM |
24 | online => "node online and member of quorate partition", |
25 | unknown => "not member of quorate partition, but possibly still running", | |
f7ccd1b3 | 26 | fence => "node needs to be fenced", |
b9e715a1 | 27 | }; |
cbca2c55 DM |
28 | |
29 | sub get_node_state { | |
30 | my ($self, $node) = @_; | |
31 | ||
f7ccd1b3 | 32 | $self->{status}->{$node} = 'unknown' |
b9e715a1 | 33 | if !$self->{status}->{$node}; |
cbca2c55 | 34 | |
b9e715a1 | 35 | return $self->{status}->{$node}; |
cbca2c55 DM |
36 | } |
37 | ||
f7ccd1b3 DM |
38 | sub node_is_online { |
39 | my ($self, $node) = @_; | |
40 | ||
41 | return $self->get_node_state($node) eq 'online'; | |
42 | } | |
43 | ||
5385a606 DM |
44 | sub node_is_offline_delayed { |
45 | my ($self, $node, $delay) = @_; | |
46 | ||
47 | return undef if $self->get_node_state($node) eq 'online'; | |
48 | ||
49 | my $last_online = $self->{last_online}->{$node}; | |
50 | ||
51 | my $ctime = time(); | |
52 | ||
53 | if (!defined($last_online)) { | |
54 | $self->{last_online}->{$node} = $ctime; | |
55 | return undef; | |
56 | } | |
57 | ||
58 | return (time() - $last_online) >= $delay; | |
59 | } | |
60 | ||
f7ccd1b3 DM |
61 | sub list_online_nodes { |
62 | my ($self) = @_; | |
63 | ||
64 | my $res = []; | |
65 | ||
c79442f2 | 66 | foreach my $node (sort keys %{$self->{status}}) { |
f7ccd1b3 DM |
67 | next if $self->{status}->{$node} ne 'online'; |
68 | push @$res, $node; | |
69 | } | |
70 | ||
71 | return $res; | |
72 | } | |
73 | ||
cbca2c55 DM |
74 | my $set_node_state = sub { |
75 | my ($self, $node, $state) = @_; | |
76 | ||
c79442f2 DM |
77 | my $haenv = $self->{haenv}; |
78 | ||
b9e715a1 DM |
79 | die "unknown node state '$state'\n" |
80 | if !defined($valid_node_states->{$state}); | |
cbca2c55 DM |
81 | |
82 | my $last_state = $self->get_node_state($node); | |
83 | ||
84 | return if $state eq $last_state; | |
85 | ||
86 | $self->{status}->{$node} = $state; | |
87 | ||
c79442f2 DM |
88 | $haenv->log('info', "node '$node': state changed from " . |
89 | "'$last_state' => '$state'\n"); | |
cbca2c55 DM |
90 | }; |
91 | ||
92 | sub update { | |
93 | my ($self, $node_info) = @_; | |
94 | ||
95 | foreach my $node (keys %$node_info) { | |
96 | my $d = $node_info->{$node}; | |
97 | next if !$d->{online}; | |
98 | ||
5385a606 DM |
99 | # record last time the node was online (required to implement fence delay) |
100 | $self->{last_online}->{$node} = time(); | |
101 | ||
cbca2c55 DM |
102 | my $state = $self->get_node_state($node); |
103 | ||
f7ccd1b3 | 104 | if ($state eq 'online') { |
c0bbd038 DM |
105 | # &$set_node_state($self, $node, 'online'); |
106 | } elsif ($state eq 'unknown') { | |
107 | &$set_node_state($self, $node, 'online'); | |
f7ccd1b3 | 108 | } elsif ($state eq 'fence') { |
c0bbd038 | 109 | # do nothing, wait until fenced |
c0bbd038 DM |
110 | } else { |
111 | die "detected unknown node state '$state"; | |
cbca2c55 DM |
112 | } |
113 | } | |
114 | ||
115 | foreach my $node (keys %{$self->{status}}) { | |
116 | my $d = $node_info->{$node}; | |
117 | next if $d && $d->{online}; | |
118 | ||
119 | my $state = $self->get_node_state($node); | |
120 | ||
c0bbd038 DM |
121 | # node is not inside quorate partition, possibly not active |
122 | ||
f7ccd1b3 | 123 | if ($state eq 'online') { |
c0bbd038 DM |
124 | &$set_node_state($self, $node, 'unknown'); |
125 | } elsif ($state eq 'unknown') { | |
126 | # &$set_node_state($self, $node, 'unknown'); | |
f7ccd1b3 | 127 | } elsif ($state eq 'fence') { |
c0bbd038 | 128 | # do nothing, wait until fenced |
c0bbd038 DM |
129 | } else { |
130 | die "detected unknown node state '$state"; | |
131 | } | |
132 | ||
cbca2c55 DM |
133 | } |
134 | } | |
135 | ||
c79442f2 | 136 | # start fencing |
f7ccd1b3 DM |
137 | sub fence_node { |
138 | my ($self, $node) = @_; | |
139 | ||
c79442f2 DM |
140 | my $haenv = $self->{haenv}; |
141 | ||
f7ccd1b3 DM |
142 | my $state = $self->get_node_state($node); |
143 | ||
c79442f2 DM |
144 | if ($state ne 'fence') { |
145 | &$set_node_state($self, $node, 'fence'); | |
f7ccd1b3 DM |
146 | } |
147 | ||
ffa555c5 DM |
148 | my $success = $haenv->test_ha_agent_lock($node); |
149 | ||
150 | if ($success) { | |
3c36cbca | 151 | $haenv->log("info", "fencing: acknowleged - got agent lock for node '$node'"); |
21e37ed4 | 152 | &$set_node_state($self, $node, 'unknown'); |
ffa555c5 DM |
153 | } |
154 | ||
155 | return $success; | |
f7ccd1b3 DM |
156 | } |
157 | ||
cbca2c55 | 158 | 1; |