]> git.proxmox.com Git - pve-ha-manager.git/blame - src/PVE/HA/FenceConfig.pm
status: mark CRM as idle if no service is configured
[pve-ha-manager.git] / src / PVE / HA / FenceConfig.pm
CommitLineData
f83e7e6e
TL
1package PVE::HA::FenceConfig;
2
3use strict;
4use warnings;
5use PVE::Tools;
6use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file);
7use Data::Dumper;
8
f83e7e6e
TL
9sub parse_config {
10 my ($fn, $raw) = @_;
11
12 $raw = '' if !$raw;
13
14 my $config = {};
15
16 my $lineno = 0;
17 my $priority = 0;
18
45e8e7b1
DM
19 eval {
20 while ($raw =~ /^\h*(.*?)\h*$/gm) {
21 my $line = $1;
22 $lineno++;
f83e7e6e 23
45e8e7b1 24 next if !$line || $line =~ /^#/;
f83e7e6e 25
45e8e7b1
DM
26 if ($line =~ m/^(device|connect)\s+(\S+)\s+(\S+)\s+(.+)$/) {
27 my ($command, $dev_name, $target) = ($1, $2, $3);
f83e7e6e 28
45e8e7b1
DM
29 # allow spaces, and other special chars inside of quoted strings
30 # with escape support
31 my @arg_array = $4 =~ /(\w+(?:=(?:(?:\"(?:[^"\\]|\\.)*\")|\S+))?)/g;
f83e7e6e 32
45e8e7b1 33 my $dev_number = 1; # default
f83e7e6e 34
45e8e7b1
DM
35 # check for parallel devices
36 if ($dev_name =~ m/^(\w+)(:(\d+))?/) {
37 $dev_name = $1;
38 $dev_number = $3 if $3;
39 }
f83e7e6e 40
45e8e7b1 41 if ($command eq "device") {
f83e7e6e 42
45e8e7b1 43 my $dev = $config->{$dev_name} || {};
f83e7e6e 44
45e8e7b1
DM
45 die "device '$dev_name:$dev_number' already declared\n"
46 if $dev && $dev->{sub_devs}->{$dev_number};
f83e7e6e 47
45e8e7b1
DM
48 $dev->{sub_devs}->{$dev_number} = {
49 agent => $target,
50 args => [ @arg_array ]
51 };
52 $dev->{priority} = $priority++ if !$dev->{priority};
f83e7e6e 53
45e8e7b1 54 $config->{$dev_name} = $dev;
f83e7e6e 55
45e8e7b1 56 } else { # connect nodes to devices
f83e7e6e 57
45e8e7b1
DM
58 die "device '$dev_name' must be declared before you can connect to it\n"
59 if !$config->{$dev_name};
f83e7e6e 60
45e8e7b1
DM
61 die "No parallel device '$dev_name:$dev_number' found\n"
62 if !$config->{$dev_name}->{sub_devs}->{$dev_number};
f83e7e6e 63
45e8e7b1 64 my $sdev = $config->{$dev_name}->{sub_devs}->{$dev_number};
f83e7e6e 65
45e8e7b1
DM
66 my ($node) = $target =~ /node=(\w+)/;
67 die "node=nodename needed to connect device '$dev_name' to node\n"
68 if !$node;
f83e7e6e 69
45e8e7b1
DM
70 die "node '$node' already connected to device '$dev_name:$dev_number'\n"
71 if $sdev->{node_args}->{$node};
f83e7e6e 72
45e8e7b1 73 $sdev->{node_args}->{$node} = [ @arg_array ];
f83e7e6e 74
45e8e7b1
DM
75 $config->{$dev_name}->{sub_devs}->{$dev_number} = $sdev;
76 }
f83e7e6e 77
45e8e7b1
DM
78 } else {
79 warn "$fn ignore line $lineno: $line\n"
f83e7e6e 80 }
f83e7e6e 81 }
45e8e7b1
DM
82 };
83 if (my $err = $@) {
84 die "error in '$fn' at $lineno: $err";
f83e7e6e
TL
85 }
86
87 return $config;
f83e7e6e
TL
88}
89
90sub write_config {
91 my ($fn, $data) = @_;
92
93 my $raw = '';
94
95 foreach my $dev_name (sort {$a->{priority} <=> $b->{priority}} keys %$data) {
96 my $d = $data->{$dev_name};
97
98 foreach my $sub_dev_nr (sort keys %{$d->{sub_devs}}) {
99 my $sub_dev = $d->{sub_devs}->{$sub_dev_nr};
100 my $dev_arg_str = join (' ', @{$sub_dev->{args}});
101
102 $raw .= "\ndevice $dev_name:$sub_dev_nr $sub_dev->{agent} $dev_arg_str\n";
103
104 foreach my $node (sort keys %{$sub_dev->{node_args}}) {
105 my $node_arg_str = join (' ', @{$sub_dev->{node_args}->{$node}});
106
107 $raw .= "connect $dev_name:$sub_dev_nr $node_arg_str\n";
108 }
109 }
110 }
111
112 return $raw;
113}
114
115
116
117sub gen_arg_str {
118 my (@arguments) = @_;
119
120 my @shell_args = ();
121 foreach my $arg (@arguments) {
122 # we need to differ long and short opts!
123 my $prefix = (length($arg) == 1) ? '-' : '--';
124 push @shell_args, "$prefix$arg";
125 }
126
127 return join (' ', @shell_args);
128}
129
130
131# returns command list to execute,
132# can be more than one command if parallel devices are configured
133# 'try' denotes the number of devices we should skip and normaly equals to
134# failed fencing tries
135sub get_commands {
136 my ($node, $try, $config) = @_;
137
138 return undef if !$node || !$config;
139
140 $try = 0 if !$try || $try<0;
141
142 foreach my $device (sort {$a->{priority} <=> $b->{priority}} values %$config) {
143 my @commands;
144
145 #foreach my $sub_dev (values %{$device->{sub_devs}}) {
146 foreach my $sub_dev_nr (sort keys %{$device->{sub_devs}}) {
147 my $sub_dev = $device->{sub_devs}->{$sub_dev_nr};
148
149 if (my $node_args = $sub_dev->{node_args}->{$node}) {
150 push @commands, { agent=>$sub_dev->{agent},
151 sub_dev => $sub_dev_nr,
152 param => [@{$sub_dev->{args}}, @{$node_args}]};
153 }
154
155 }
156
157 if (@commands>0) {
158 $try--;
159 return [ @commands ] if $try<0;
160 }
161 }
162
163 # out of tries or no device for this node
164 return undef;
165}
166
167
168sub count_devices {
169 my ($node, $config) = @_;
170
171 my $count = 0;
172
173 return 0 if !$config;
174
175 foreach my $device (values %$config) {
176 foreach my $sub_dev (values %{$device->{sub_devs}}) {
177 if ($sub_dev->{node_args}->{$node}) {
178 $count++;
179 last; # no need to count parallel devices
180 }
181 }
182 }
183
184 return $count;
185}
186
1871;