]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/HA/Tools.pm
bump version to 1.0-21
[pve-ha-manager.git] / src / PVE / HA / Tools.pm
CommitLineData
54fc75de
DM
1package PVE::HA::Tools;
2
3use strict;
4use warnings;
a223f4cc
DM
5use JSON;
6use PVE::JSONSchema;
54fc75de 7use PVE::Tools;
427e33b6 8use PVE::Cluster;
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,
21};
22
23# get constants out of package in a somewhat easy way
24use base 'Exporter';
25our @EXPORT_OK = qw(SUCCESS ERROR EWRONG_NODE EUNKNOWN_SERVICE_TYPE
26 EUNKNOWN_COMMAND EINVALID_PARAMETER ETRY_AGAIN);
27our %EXPORT_TAGS = ( 'exit_codes' => [@EXPORT_OK] );
28
95ea5d67
DM
29PVE::JSONSchema::register_format('pve-ha-resource-id', \&pve_verify_ha_resource_id);
30sub pve_verify_ha_resource_id {
31 my ($sid, $noerr) = @_;
32
33 if ($sid !~ m/^[a-z]+:\S+$/) {
34 return undef if $noerr;
35 die "value does not look like a valid ha resource id\n";
36 }
37 return $sid;
38}
39
40PVE::JSONSchema::register_standard_option('pve-ha-resource-id', {
427e33b6 41 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
DM
42 typetext => "<type>:<name>",
43 type => 'string', format => 'pve-ha-resource-id',
44});
45
6ca2edcd
DM
46PVE::JSONSchema::register_format('pve-ha-resource-or-vm-id', \&pve_verify_ha_resource_or_vm_id);
47sub pve_verify_ha_resource_or_vm_id {
48 my ($sid, $noerr) = @_;
49
50 if ($sid !~ m/^([a-z]+:\S+|\d+)$/) {
51 return undef if $noerr;
52 die "value does not look like a valid ha resource id\n";
53 }
54 return $sid;
55}
56
57PVE::JSONSchema::register_standard_option('pve-ha-resource-or-vm-id', {
427e33b6 58 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
DM
59 typetext => "<type>:<name>",
60 type => 'string', format => 'pve-ha-resource-or-vm-id',
61});
62
a223f4cc
DM
63PVE::JSONSchema::register_format('pve-ha-group-node', \&pve_verify_ha_group_node);
64sub pve_verify_ha_group_node {
65 my ($node, $noerr) = @_;
66
67 if ($node !~ m/^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)(:\d+)?$/) {
68 return undef if $noerr;
69 die "value does not look like a valid ha group node\n";
70 }
71 return $node;
72}
73
74PVE::JSONSchema::register_standard_option('pve-ha-group-node-list', {
63f6a08c 75 description => "List of cluster node names with optional priority. We use priority '0' as default. The CRM tries to run services on the node with highest priority (also see option 'nofailback').",
a223f4cc
DM
76 type => 'string', format => 'pve-ha-group-node-list',
77 typetext => '<node>[:<pri>]{,<node>[:<pri>]}*',
78});
79
80PVE::JSONSchema::register_standard_option('pve-ha-group-id', {
81 description => "The HA group identifier.",
82 type => 'string', format => 'pve-configid',
83});
84
b47a7a1b
DM
85sub parse_sid {
86 my ($sid) = @_;
87
6ca2edcd
DM
88 my ($type, $name);
89
90 if ($sid =~ m/^(\d+)$/) {
91 $name = $1;
427e33b6
AG
92 my $vmlist = PVE::Cluster::get_vmlist();
93 if (defined($vmlist->{ids}->{$name})) {
94 my $vm_type = $vmlist->{ids}->{$name}->{type};
95 if ($vm_type eq 'lxc') {
96 $type = 'ct';
97 } elsif ($vm_type eq 'qemu') {
98 $type = 'vm';
99 } else {
100 die "internal error";
101 }
102 $sid = "$type:$name";
103 }
104 else {
105 die "unable do add resource - VM/CT $1 does not exist\n";
106 }
6ca2edcd
DM
107 } elsif ($sid =~m/^(\S+):(\S+)$/) {
108 $name = $2;
109 $type = $1;
110 } else {
111 die "unable to parse service id '$sid'\n";
112 }
b47a7a1b 113
6ca2edcd 114 return wantarray ? ($sid, $type, $name) : $sid;
b47a7a1b
DM
115}
116
54fc75de
DM
117sub read_json_from_file {
118 my ($filename, $default) = @_;
119
120 my $data;
121
122 if (defined($default) && (! -f $filename)) {
123 $data = $default;
124 } else {
3b8cba06
DM
125 my $raw;
126 # workaround for bug #775
127 if ($filename =~ m|^/etc/pve/|) {
128 $filename =~ s|^/etc/pve/+||;
129 $raw = PVE::Cluster::get_config($filename);
130 die "unable to read file '/etc/pve/$filename'\n"
131 if !defined($raw);
132 } else {
133 $raw = PVE::Tools::file_get_contents($filename);
134 }
54fc75de
DM
135 $data = decode_json($raw);
136 }
137
138 return $data;
139}
140
141sub write_json_to_file {
142 my ($filename, $data) = @_;
143
144 my $raw = encode_json($data);
a223f4cc 145
54fc75de
DM
146 PVE::Tools::file_set_contents($filename, $raw);
147}
148
49777d09
DM
149sub count_fenced_services {
150 my ($ss, $node) = @_;
151
152 my $count = 0;
153
154 foreach my $sid (keys %$ss) {
155 my $sd = $ss->{$sid};
156 next if !$sd->{node};
157 next if $sd->{node} ne $node;
158 my $req_state = $sd->{state};
159 next if !defined($req_state);
160 if ($req_state eq 'fence') {
161 $count++;
162 next;
163 }
164 }
165
166 return $count;
167}
54fc75de 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
182sub complete_sid {
bf119a50 183 my ($cmd, $pname, $cur) = @_;
cdf272a0 184
bf119a50 185 my $cfg = PVE::HA::Config::read_resources_config();
cdf272a0
TL
186
187 my $res = [];
cdf272a0 188
bf119a50 189 if ($cmd eq 'add') {
cdf272a0 190
bf119a50
DM
191 my $vmlist = PVE::Cluster::get_vmlist();
192
193 while (my ($vmid, $info) = each %{$vmlist->{ids}}) {
194
195 my $sid;
196
197 if ($info->{type} eq 'lxc') {
198 $sid = "ct:$vmid";
199 } elsif ($info->{type} eq 'qemu') {
200 $sid = "vm:$vmid";
201 } else {
202 next; # should not happen
203 }
204
205 next if $cfg->{ids}->{$sid};
206
207 push @$res, $sid;
208 }
209
210 } else {
211
212 foreach my $sid (keys %{$cfg->{ids}}) {
213 push @$res, $sid;
cdf272a0 214 }
bf119a50 215 }
cdf272a0 216
bf119a50
DM
217 return $res;
218}
219
220sub complete_enabled_sid {
221
222 my $cfg = PVE::HA::Config::read_resources_config();
cdf272a0 223
bf119a50
DM
224 my $res = [];
225 foreach my $sid (keys %{$cfg->{ids}}) {
226 my $state = $cfg->{ids}->{$sid}->{state} // 'enabled';
227 next if $state ne 'enabled';
cdf272a0 228 push @$res, $sid;
bf119a50 229 }
cdf272a0 230
bf119a50
DM
231 return $res;
232}
233
234sub complete_disabled_sid {
235
236 my $cfg = PVE::HA::Config::read_resources_config();
237
238 my $res = [];
239 foreach my $sid (keys %{$cfg->{ids}}) {
240 my $state = $cfg->{ids}->{$sid}->{state} // 'enabled';
241 next if $state eq 'enabled';
242 push @$res, $sid;
cdf272a0
TL
243 }
244
245 return $res;
246}
247
248sub complete_group {
bc544941 249 my ($cmd, $pname, $cur) = @_;
cdf272a0
TL
250
251 my $cfg = PVE::HA::Config::read_group_config();
252
253 my $res = [];
bc544941
TL
254 if ($cmd ne 'groupadd') {
255
256 foreach my $group (keys %{$cfg->{ids}}) {
257 push @$res, $group;
258 }
259
cdf272a0
TL
260 }
261
262 return $res;
263}
264
265
54fc75de 2661;