1 package PVE
::HA
::Tools
;
11 # return codes used in the ha environment
12 # mainly by the resource agents
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,
23 # get constants out of package in a somewhat easy way
25 our @EXPORT_OK = qw(SUCCESS ERROR EWRONG_NODE EUNKNOWN_SERVICE_TYPE
26 EUNKNOWN_COMMAND EINVALID_PARAMETER ETRY_AGAIN);
27 our %EXPORT_TAGS = ( 'exit_codes' => [@EXPORT_OK] );
29 PVE
::JSONSchema
::register_format
('pve-ha-resource-id', \
&pve_verify_ha_resource_id
);
30 sub pve_verify_ha_resource_id
{
31 my ($sid, $noerr) = @_;
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";
40 PVE
::JSONSchema
::register_standard_option
('pve-ha-resource-id', {
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).",
42 typetext
=> "<type>:<name>",
43 type
=> 'string', format
=> 'pve-ha-resource-id',
46 PVE
::JSONSchema
::register_format
('pve-ha-resource-or-vm-id', \
&pve_verify_ha_resource_or_vm_id
);
47 sub pve_verify_ha_resource_or_vm_id
{
48 my ($sid, $noerr) = @_;
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";
57 PVE
::JSONSchema
::register_standard_option
('pve-ha-resource-or-vm-id', {
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).",
59 typetext
=> "<type>:<name>",
60 type
=> 'string', format
=> 'pve-ha-resource-or-vm-id',
63 PVE
::JSONSchema
::register_format
('pve-ha-group-node', \
&pve_verify_ha_group_node
);
64 sub pve_verify_ha_group_node
{
65 my ($node, $noerr) = @_;
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";
74 PVE
::JSONSchema
::register_standard_option
('pve-ha-group-node-list', {
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').",
76 type
=> 'string', format
=> 'pve-ha-group-node-list',
77 typetext
=> '<node>[:<pri>]{,<node>[:<pri>]}*',
80 PVE
::JSONSchema
::register_standard_option
('pve-ha-group-id', {
81 description
=> "The HA group identifier.",
82 type
=> 'string', format
=> 'pve-configid',
90 if ($sid =~ m/^(\d+)$/) {
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') {
97 } elsif ($vm_type eq 'qemu') {
100 die "internal error";
102 $sid = "$type:$name";
105 die "unable do add resource - VM/CT $1 does not exist\n";
107 } elsif ($sid =~m/^(\S+):(\S+)$/) {
111 die "unable to parse service id '$sid'\n";
114 return wantarray ?
($sid, $type, $name) : $sid;
117 sub read_json_from_file
{
118 my ($filename, $default) = @_;
122 if (defined($default) && (! -f
$filename)) {
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"
133 $raw = PVE
::Tools
::file_get_contents
($filename);
135 $data = decode_json
($raw);
141 sub write_json_to_file
{
142 my ($filename, $data) = @_;
144 my $raw = encode_json
($data);
146 PVE
::Tools
::file_set_contents
($filename, $raw);
149 sub count_fenced_services
{
150 my ($ss, $node) = @_;
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') {
170 my ($upid, $haenv) = @_;
173 my $task = PVE
::Tools
::upid_encode
(shift);
174 $haenv->log('info', "Task '$task' still active, waiting");
177 PVE
::ProcFSTools
::upid_wait
($upid, $waitfunc, 5);
180 # bash auto completion helper
183 my ($cmd, $pname, $cur) = @_;
185 my $cfg = PVE
::HA
::Config
::read_resources_config
();
191 my $vmlist = PVE
::Cluster
::get_vmlist
();
193 while (my ($vmid, $info) = each %{$vmlist->{ids
}}) {
197 if ($info->{type
} eq 'lxc') {
199 } elsif ($info->{type
} eq 'qemu') {
202 next; # should not happen
205 next if $cfg->{ids
}->{$sid};
212 foreach my $sid (keys %{$cfg->{ids
}}) {
220 sub complete_enabled_sid
{
222 my $cfg = PVE
::HA
::Config
::read_resources_config
();
225 foreach my $sid (keys %{$cfg->{ids
}}) {
226 my $state = $cfg->{ids
}->{$sid}->{state} // 'enabled';
227 next if $state ne 'enabled';
234 sub complete_disabled_sid
{
236 my $cfg = PVE
::HA
::Config
::read_resources_config
();
239 foreach my $sid (keys %{$cfg->{ids
}}) {
240 my $state = $cfg->{ids
}->{$sid}->{state} // 'enabled';
241 next if $state eq 'enabled';
249 my ($cmd, $pname, $cur) = @_;
251 my $cfg = PVE
::HA
::Config
::read_group_config
();
254 if ($cmd ne 'groupadd') {
256 foreach my $group (keys %{$cfg->{ids
}}) {