]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/HA/Tools.pm
tools: add IGNORED return code
[pve-ha-manager.git] / src / PVE / HA / Tools.pm
CommitLineData
54fc75de
DM
1package PVE::HA::Tools;
2
3use strict;
4use warnings;
a223f4cc 5use JSON;
0087839a 6
a223f4cc 7use PVE::JSONSchema;
54fc75de 8use PVE::Tools;
33783485 9use PVE::ProcFSTools;
54fc75de 10
80ec7386
TL
11# return codes used in the ha environment
12# mainly by the resource agents
13use constant {
14 SUCCESS => 0, # action finished as expected
15 ERROR => 1, # action was erroneous
16 ETRY_AGAIN => 2, # action was erroneous and needs to be repeated
17 EWRONG_NODE => 3, # needs to fixup the service location
18 EUNKNOWN_SERVICE_TYPE => 4, # no plugin for this type service found
19 EUNKNOWN_COMMAND => 5,
20 EINVALID_PARAMETER => 6,
aaabde6a 21 EUNKNOWN_SERVICE => 7, # service not found
c0dbab3c 22 IGNORED => 8, # action was ignored for some good reason
80ec7386
TL
23};
24
25# get constants out of package in a somewhat easy way
26use base 'Exporter';
27our @EXPORT_OK = qw(SUCCESS ERROR EWRONG_NODE EUNKNOWN_SERVICE_TYPE
c0dbab3c 28 EUNKNOWN_COMMAND EINVALID_PARAMETER ETRY_AGAIN EUNKNOWN_SERVICE IGNORED);
80ec7386
TL
29our %EXPORT_TAGS = ( 'exit_codes' => [@EXPORT_OK] );
30
95ea5d67
DM
31PVE::JSONSchema::register_format('pve-ha-resource-id', \&pve_verify_ha_resource_id);
32sub pve_verify_ha_resource_id {
33 my ($sid, $noerr) = @_;
34
35 if ($sid !~ m/^[a-z]+:\S+$/) {
36 return undef if $noerr;
37 die "value does not look like a valid ha resource id\n";
38 }
39 return $sid;
40}
41
42PVE::JSONSchema::register_standard_option('pve-ha-resource-id', {
427e33b6 43 description => "HA resource ID. This consists of a resource type followed by a resource specific name, separated with colon (example: vm:100 / ct:100).",
95ea5d67 44 typetext => "<type>:<name>",
289e4784 45 type => 'string', format => 'pve-ha-resource-id',
95ea5d67
DM
46});
47
6ca2edcd
DM
48PVE::JSONSchema::register_format('pve-ha-resource-or-vm-id', \&pve_verify_ha_resource_or_vm_id);
49sub pve_verify_ha_resource_or_vm_id {
50 my ($sid, $noerr) = @_;
51
52 if ($sid !~ m/^([a-z]+:\S+|\d+)$/) {
53 return undef if $noerr;
54 die "value does not look like a valid ha resource id\n";
55 }
56 return $sid;
57}
58
59PVE::JSONSchema::register_standard_option('pve-ha-resource-or-vm-id', {
427e33b6 60 description => "HA resource ID. This consists of a resource type followed by a resource specific name, separated with colon (example: vm:100 / ct:100). For virtual machines and containers, you can simply use the VM or CT id as a shortcut (example: 100).",
6ca2edcd 61 typetext => "<type>:<name>",
289e4784 62 type => 'string', format => 'pve-ha-resource-or-vm-id',
6ca2edcd
DM
63});
64
a223f4cc
DM
65PVE::JSONSchema::register_format('pve-ha-group-node', \&pve_verify_ha_group_node);
66sub pve_verify_ha_group_node {
67 my ($node, $noerr) = @_;
68
69 if ($node !~ m/^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)(:\d+)?$/) {
70 return undef if $noerr;
71 die "value does not look like a valid ha group node\n";
72 }
73 return $node;
74}
75
76PVE::JSONSchema::register_standard_option('pve-ha-group-node-list', {
8eac610f
DM
77 description => "List of cluster node names with optional priority.",
78 verbose_description => "List of cluster node members, where a priority can be given to each node. A resource bound to a group will run on the available nodes with the highest priority. If there are more nodes in the highest priority class, the services will get distributed to those nodes. The priorities have a relative meaning only.",
a223f4cc
DM
79 type => 'string', format => 'pve-ha-group-node-list',
80 typetext => '<node>[:<pri>]{,<node>[:<pri>]}*',
81});
82
83PVE::JSONSchema::register_standard_option('pve-ha-group-id', {
84 description => "The HA group identifier.",
85 type => 'string', format => 'pve-configid',
86});
87
54fc75de
DM
88sub read_json_from_file {
89 my ($filename, $default) = @_;
90
91 my $data;
92
93 if (defined($default) && (! -f $filename)) {
94 $data = $default;
95 } else {
6529b6a4 96 my $raw = PVE::Tools::file_get_contents($filename);
54fc75de
DM
97 $data = decode_json($raw);
98 }
99
100 return $data;
101}
102
103sub write_json_to_file {
104 my ($filename, $data) = @_;
105
106 my $raw = encode_json($data);
a223f4cc 107
54fc75de
DM
108 PVE::Tools::file_set_contents($filename, $raw);
109}
110
49777d09
DM
111sub count_fenced_services {
112 my ($ss, $node) = @_;
113
114 my $count = 0;
289e4784 115
49777d09
DM
116 foreach my $sid (keys %$ss) {
117 my $sd = $ss->{$sid};
118 next if !$sd->{node};
119 next if $sd->{node} ne $node;
120 my $req_state = $sd->{state};
121 next if !defined($req_state);
122 if ($req_state eq 'fence') {
123 $count++;
124 next;
125 }
126 }
289e4784 127
49777d09
DM
128 return $count;
129}
54fc75de 130
aa68337a
TL
131sub get_verbose_service_state {
132 my ($service_state, $service_conf) = @_;
133
dcb4a2a4
TL
134 return 'deleting' if !$service_conf;
135
dab49a14
TL
136 my $req = $service_conf->{state} // 'ignored';
137 return 'ignored' if $req eq 'ignored';
138
fbda2658
TL
139 return 'not found' if !defined($service_conf->{node});
140
aa68337a
TL
141 # service not yet processed by manager
142 return 'queued' if !defined($service_state);
143 my $cur = $service_state->{state};
144
aa68337a
TL
145 # give fast feedback to the user
146 my $state = $cur;
147 if (!defined($cur)) {
148 $state = 'queued';
149 } elsif ($cur eq 'stopped') {
150 if ($req eq 'started') {
151 $state = 'starting';
152 } elsif ($req eq 'disabled') {
153 $state = 'disabled';
154 }
155 } elsif ($cur eq 'started') {
156 if ($req eq 'stopped' || $req eq 'disabled') {
157 $state = 'stopping';
158 }
159 $state = 'starting' if !$service_state->{running};
160 } elsif ($cur eq 'error') {
161 if ($req eq 'disabled') {
162 $state = 'clearing error flag';
163 }
164 }
165
166 return $state;
167}
168
33783485
TL
169sub upid_wait {
170 my ($upid, $haenv) = @_;
171
172 my $waitfunc = sub {
173 my $task = PVE::Tools::upid_encode(shift);
174 $haenv->log('info', "Task '$task' still active, waiting");
175 };
176
177 PVE::ProcFSTools::upid_wait($upid, $waitfunc, 5);
178}
179
cdf272a0
TL
180# bash auto completion helper
181
1e07d70c
TL
182# NOTE: we use PVE::HA::Config here without declaring an 'use' clause above as
183# an hack. It uses the PVE::Cluster module from pve-cluster, which we do not
184# have nor want as dependency in the simulator - where the completion helpers
185# are never called. The PVE::CLI::ha_manager package pulls it in for us.
186
cdf272a0 187sub complete_sid {
bf119a50 188 my ($cmd, $pname, $cur) = @_;
cdf272a0 189
bf119a50 190 my $cfg = PVE::HA::Config::read_resources_config();
cdf272a0
TL
191
192 my $res = [];
cdf272a0 193
bf119a50 194 if ($cmd eq 'add') {
cdf272a0 195
bf119a50
DM
196 my $vmlist = PVE::Cluster::get_vmlist();
197
198 while (my ($vmid, $info) = each %{$vmlist->{ids}}) {
199
200 my $sid;
201
202 if ($info->{type} eq 'lxc') {
203 $sid = "ct:$vmid";
204 } elsif ($info->{type} eq 'qemu') {
205 $sid = "vm:$vmid";
206 } else {
207 next; # should not happen
208 }
209
210 next if $cfg->{ids}->{$sid};
211
212 push @$res, $sid;
213 }
214
215 } else {
216
217 foreach my $sid (keys %{$cfg->{ids}}) {
218 push @$res, $sid;
cdf272a0 219 }
bf119a50 220 }
cdf272a0 221
bf119a50
DM
222 return $res;
223}
224
225sub complete_enabled_sid {
bf119a50 226 my $cfg = PVE::HA::Config::read_resources_config();
cdf272a0 227
bf119a50
DM
228 my $res = [];
229 foreach my $sid (keys %{$cfg->{ids}}) {
bb07bd2c
TL
230 my $state = $cfg->{ids}->{$sid}->{state} // 'started';
231 next if $state ne 'started';
cdf272a0 232 push @$res, $sid;
bf119a50 233 }
cdf272a0 234
bf119a50
DM
235 return $res;
236}
237
238sub complete_disabled_sid {
bf119a50
DM
239 my $cfg = PVE::HA::Config::read_resources_config();
240
241 my $res = [];
242 foreach my $sid (keys %{$cfg->{ids}}) {
bb07bd2c
TL
243 my $state = $cfg->{ids}->{$sid}->{state} // 'started';
244 next if $state eq 'started';
bf119a50 245 push @$res, $sid;
cdf272a0
TL
246 }
247
248 return $res;
249}
250
251sub complete_group {
bc544941 252 my ($cmd, $pname, $cur) = @_;
cdf272a0
TL
253
254 my $cfg = PVE::HA::Config::read_group_config();
255
256 my $res = [];
bc544941
TL
257 if ($cmd ne 'groupadd') {
258
259 foreach my $group (keys %{$cfg->{ids}}) {
260 push @$res, $group;
261 }
262
cdf272a0
TL
263 }
264
265 return $res;
266}
267
54fc75de 2681;