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