]>
Commit | Line | Data |
---|---|---|
54fc75de DM |
1 | package PVE::HA::Tools; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
a223f4cc DM |
5 | use JSON; |
6 | use PVE::JSONSchema; | |
54fc75de | 7 | use PVE::Tools; |
427e33b6 | 8 | use PVE::Cluster; |
54fc75de | 9 | |
95ea5d67 DM |
10 | PVE::JSONSchema::register_format('pve-ha-resource-id', \&pve_verify_ha_resource_id); |
11 | sub pve_verify_ha_resource_id { | |
12 | my ($sid, $noerr) = @_; | |
13 | ||
14 | if ($sid !~ m/^[a-z]+:\S+$/) { | |
15 | return undef if $noerr; | |
16 | die "value does not look like a valid ha resource id\n"; | |
17 | } | |
18 | return $sid; | |
19 | } | |
20 | ||
21 | PVE::JSONSchema::register_standard_option('pve-ha-resource-id', { | |
427e33b6 | 22 | 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 |
23 | typetext => "<type>:<name>", |
24 | type => 'string', format => 'pve-ha-resource-id', | |
25 | }); | |
26 | ||
6ca2edcd DM |
27 | PVE::JSONSchema::register_format('pve-ha-resource-or-vm-id', \&pve_verify_ha_resource_or_vm_id); |
28 | sub pve_verify_ha_resource_or_vm_id { | |
29 | my ($sid, $noerr) = @_; | |
30 | ||
31 | if ($sid !~ m/^([a-z]+:\S+|\d+)$/) { | |
32 | return undef if $noerr; | |
33 | die "value does not look like a valid ha resource id\n"; | |
34 | } | |
35 | return $sid; | |
36 | } | |
37 | ||
38 | PVE::JSONSchema::register_standard_option('pve-ha-resource-or-vm-id', { | |
427e33b6 | 39 | 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 |
40 | typetext => "<type>:<name>", |
41 | type => 'string', format => 'pve-ha-resource-or-vm-id', | |
42 | }); | |
43 | ||
a223f4cc DM |
44 | PVE::JSONSchema::register_format('pve-ha-group-node', \&pve_verify_ha_group_node); |
45 | sub pve_verify_ha_group_node { | |
46 | my ($node, $noerr) = @_; | |
47 | ||
48 | if ($node !~ m/^([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)(:\d+)?$/) { | |
49 | return undef if $noerr; | |
50 | die "value does not look like a valid ha group node\n"; | |
51 | } | |
52 | return $node; | |
53 | } | |
54 | ||
55 | PVE::JSONSchema::register_standard_option('pve-ha-group-node-list', { | |
56 | 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 higest priority (also see option 'nofailback').", | |
57 | type => 'string', format => 'pve-ha-group-node-list', | |
58 | typetext => '<node>[:<pri>]{,<node>[:<pri>]}*', | |
59 | }); | |
60 | ||
61 | PVE::JSONSchema::register_standard_option('pve-ha-group-id', { | |
62 | description => "The HA group identifier.", | |
63 | type => 'string', format => 'pve-configid', | |
64 | }); | |
65 | ||
b47a7a1b DM |
66 | sub parse_sid { |
67 | my ($sid) = @_; | |
68 | ||
6ca2edcd DM |
69 | my ($type, $name); |
70 | ||
71 | if ($sid =~ m/^(\d+)$/) { | |
72 | $name = $1; | |
427e33b6 AG |
73 | my $vmlist = PVE::Cluster::get_vmlist(); |
74 | if (defined($vmlist->{ids}->{$name})) { | |
75 | my $vm_type = $vmlist->{ids}->{$name}->{type}; | |
76 | if ($vm_type eq 'lxc') { | |
77 | $type = 'ct'; | |
78 | } elsif ($vm_type eq 'qemu') { | |
79 | $type = 'vm'; | |
80 | } else { | |
81 | die "internal error"; | |
82 | } | |
83 | $sid = "$type:$name"; | |
84 | } | |
85 | else { | |
86 | die "unable do add resource - VM/CT $1 does not exist\n"; | |
87 | } | |
6ca2edcd DM |
88 | } elsif ($sid =~m/^(\S+):(\S+)$/) { |
89 | $name = $2; | |
90 | $type = $1; | |
91 | } else { | |
92 | die "unable to parse service id '$sid'\n"; | |
93 | } | |
b47a7a1b | 94 | |
6ca2edcd | 95 | return wantarray ? ($sid, $type, $name) : $sid; |
b47a7a1b DM |
96 | } |
97 | ||
54fc75de DM |
98 | sub read_json_from_file { |
99 | my ($filename, $default) = @_; | |
100 | ||
101 | my $data; | |
102 | ||
103 | if (defined($default) && (! -f $filename)) { | |
104 | $data = $default; | |
105 | } else { | |
106 | my $raw = PVE::Tools::file_get_contents($filename); | |
107 | $data = decode_json($raw); | |
108 | } | |
109 | ||
110 | return $data; | |
111 | } | |
112 | ||
113 | sub write_json_to_file { | |
114 | my ($filename, $data) = @_; | |
115 | ||
116 | my $raw = encode_json($data); | |
a223f4cc | 117 | |
54fc75de DM |
118 | PVE::Tools::file_set_contents($filename, $raw); |
119 | } | |
120 | ||
49777d09 DM |
121 | sub count_fenced_services { |
122 | my ($ss, $node) = @_; | |
123 | ||
124 | my $count = 0; | |
125 | ||
126 | foreach my $sid (keys %$ss) { | |
127 | my $sd = $ss->{$sid}; | |
128 | next if !$sd->{node}; | |
129 | next if $sd->{node} ne $node; | |
130 | my $req_state = $sd->{state}; | |
131 | next if !defined($req_state); | |
132 | if ($req_state eq 'fence') { | |
133 | $count++; | |
134 | next; | |
135 | } | |
136 | } | |
137 | ||
138 | return $count; | |
139 | } | |
54fc75de | 140 | |
cdf272a0 TL |
141 | # bash auto completion helper |
142 | ||
143 | sub complete_sid { | |
bf119a50 | 144 | my ($cmd, $pname, $cur) = @_; |
cdf272a0 | 145 | |
bf119a50 | 146 | my $cfg = PVE::HA::Config::read_resources_config(); |
cdf272a0 TL |
147 | |
148 | my $res = []; | |
cdf272a0 | 149 | |
bf119a50 | 150 | if ($cmd eq 'add') { |
cdf272a0 | 151 | |
bf119a50 DM |
152 | my $vmlist = PVE::Cluster::get_vmlist(); |
153 | ||
154 | while (my ($vmid, $info) = each %{$vmlist->{ids}}) { | |
155 | ||
156 | my $sid; | |
157 | ||
158 | if ($info->{type} eq 'lxc') { | |
159 | $sid = "ct:$vmid"; | |
160 | } elsif ($info->{type} eq 'qemu') { | |
161 | $sid = "vm:$vmid"; | |
162 | } else { | |
163 | next; # should not happen | |
164 | } | |
165 | ||
166 | next if $cfg->{ids}->{$sid}; | |
167 | ||
168 | push @$res, $sid; | |
169 | } | |
170 | ||
171 | } else { | |
172 | ||
173 | foreach my $sid (keys %{$cfg->{ids}}) { | |
174 | push @$res, $sid; | |
cdf272a0 | 175 | } |
bf119a50 | 176 | } |
cdf272a0 | 177 | |
bf119a50 DM |
178 | return $res; |
179 | } | |
180 | ||
181 | sub complete_enabled_sid { | |
182 | ||
183 | my $cfg = PVE::HA::Config::read_resources_config(); | |
cdf272a0 | 184 | |
bf119a50 DM |
185 | my $res = []; |
186 | foreach my $sid (keys %{$cfg->{ids}}) { | |
187 | my $state = $cfg->{ids}->{$sid}->{state} // 'enabled'; | |
188 | next if $state ne 'enabled'; | |
cdf272a0 | 189 | push @$res, $sid; |
bf119a50 | 190 | } |
cdf272a0 | 191 | |
bf119a50 DM |
192 | return $res; |
193 | } | |
194 | ||
195 | sub complete_disabled_sid { | |
196 | ||
197 | my $cfg = PVE::HA::Config::read_resources_config(); | |
198 | ||
199 | my $res = []; | |
200 | foreach my $sid (keys %{$cfg->{ids}}) { | |
201 | my $state = $cfg->{ids}->{$sid}->{state} // 'enabled'; | |
202 | next if $state eq 'enabled'; | |
203 | push @$res, $sid; | |
cdf272a0 TL |
204 | } |
205 | ||
206 | return $res; | |
207 | } | |
208 | ||
209 | sub complete_group { | |
210 | ||
211 | my $cfg = PVE::HA::Config::read_group_config(); | |
212 | ||
213 | my $res = []; | |
214 | foreach my $group (keys %{$cfg->{ids}}) { | |
215 | push @$res, $group; | |
216 | } | |
217 | ||
218 | return $res; | |
219 | } | |
220 | ||
221 | ||
54fc75de | 222 | 1; |