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