]>
Commit | Line | Data |
---|---|---|
b6973a89 TL |
1 | package PVE::Corosync; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | ||
6 | use Digest::SHA; | |
496de919 | 7 | use Clone 'clone'; |
b6973a89 TL |
8 | |
9 | use PVE::Cluster; | |
10 | ||
11 | my $basedir = "/etc/pve"; | |
12 | ||
496de919 TL |
13 | my $conf_array_sections = { |
14 | node => 1, | |
15 | interface => 1, | |
16 | }; | |
17 | ||
b6973a89 TL |
18 | # a very simply parser ... |
19 | sub parse_conf { | |
20 | my ($filename, $raw) = @_; | |
21 | ||
22 | return {} if !$raw; | |
23 | ||
24 | my $digest = Digest::SHA::sha1_hex(defined($raw) ? $raw : ''); | |
25 | ||
26 | $raw =~ s/#.*$//mg; | |
27 | $raw =~ s/\r?\n/ /g; | |
28 | $raw =~ s/\s+/ /g; | |
29 | $raw =~ s/^\s+//; | |
30 | $raw =~ s/\s*$//; | |
31 | ||
32 | my @tokens = split(/\s/, $raw); | |
33 | ||
496de919 | 34 | my $conf = { 'main' => {} }; |
b6973a89 TL |
35 | |
36 | my $stack = []; | |
496de919 | 37 | my $section = $conf->{main}; |
b6973a89 TL |
38 | |
39 | while (defined(my $token = shift @tokens)) { | |
40 | my $nexttok = $tokens[0]; | |
41 | ||
42 | if ($nexttok && ($nexttok eq '{')) { | |
43 | shift @tokens; # skip '{' | |
496de919 TL |
44 | my $new_section = {}; |
45 | if ($conf_array_sections->{$token}) { | |
46 | $section->{$token} = [] if !defined($section->{$token}); | |
47 | push @{$section->{$token}}, $new_section; | |
48 | } elsif (!defined($section->{$token})) { | |
49 | $section->{$token} = $new_section; | |
50 | } else { | |
51 | die "section '$token' already exists and not marked as array!\n"; | |
52 | } | |
b6973a89 TL |
53 | push @$stack, $section; |
54 | $section = $new_section; | |
55 | next; | |
56 | } | |
57 | ||
58 | if ($token eq '}') { | |
59 | $section = pop @$stack; | |
60 | die "parse error - uncexpected '}'\n" if !$section; | |
61 | next; | |
62 | } | |
63 | ||
64 | my $key = $token; | |
65 | die "missing ':' after key '$key'\n" if ! ($key =~ s/:$//); | |
66 | ||
67 | die "parse error - no value for '$key'\n" if !defined($nexttok); | |
68 | my $value = shift @tokens; | |
69 | ||
496de919 | 70 | $section->{$key} = $value; |
b6973a89 TL |
71 | } |
72 | ||
e7ecad20 TL |
73 | # make working with the config way easier |
74 | my ($totem, $nodelist) = $conf->{main}->@{"totem", "nodelist"}; | |
75 | $nodelist->{node} = { map { $_->{name} // $_->{ring0_addr} => $_ } @{$nodelist->{node}} }; | |
76 | $totem->{interface} = { map { $_->{ringnumber} => $_ } @{$totem->{interface}} }; | |
77 | ||
b6973a89 TL |
78 | $conf->{digest} = $digest; |
79 | ||
80 | return $conf; | |
81 | } | |
82 | ||
83 | my $dump_section; | |
84 | $dump_section = sub { | |
85 | my ($section, $prefix) = @_; | |
86 | ||
496de919 | 87 | my $raw = ''; |
b6973a89 | 88 | |
496de919 TL |
89 | foreach my $k (sort keys %$section) { |
90 | my $v = $section->{$k}; | |
91 | if (ref($v) eq 'HASH') { | |
92 | $raw .= $prefix . "$k {\n"; | |
93 | $raw .= &$dump_section($v, "$prefix "); | |
94 | $raw .= $prefix . "}\n"; | |
95 | $raw .= "\n" if !$prefix; # add extra newline at 1st level only | |
96 | } elsif (ref($v) eq 'ARRAY') { | |
97 | foreach my $child (@$v) { | |
98 | $raw .= $prefix . "$k {\n"; | |
99 | $raw .= &$dump_section($child, "$prefix "); | |
100 | $raw .= $prefix . "}\n"; | |
101 | } | |
102 | } elsif (!ref($v)) { | |
103 | $raw .= $prefix . "$k: $v\n"; | |
104 | } else { | |
105 | die "unexpected reference in config hash: $k => ". ref($v) ."\n"; | |
106 | } | |
b6973a89 TL |
107 | } |
108 | ||
b6973a89 | 109 | return $raw; |
b6973a89 TL |
110 | }; |
111 | ||
112 | sub write_conf { | |
113 | my ($filename, $conf) = @_; | |
114 | ||
e7ecad20 TL |
115 | my $c = clone($conf->{main}) // die "no main section"; |
116 | ||
117 | # retransform back for easier dumping | |
118 | my $hash_to_array = sub { | |
119 | my ($hash) = @_; | |
120 | return [ $hash->@{sort keys %$hash} ]; | |
121 | }; | |
b6973a89 | 122 | |
e7ecad20 TL |
123 | $c->{nodelist}->{node} = &$hash_to_array($c->{nodelist}->{node}); |
124 | $c->{totem}->{interface} = &$hash_to_array($c->{totem}->{interface}); | |
125 | ||
126 | my $raw = &$dump_section($c, ''); | |
b6973a89 TL |
127 | |
128 | return $raw; | |
129 | } | |
130 | ||
131 | sub conf_version { | |
132 | my ($conf, $noerr, $new_value) = @_; | |
133 | ||
496de919 TL |
134 | my $totem = $conf->{main}->{totem}; |
135 | if (defined($totem) && defined($totem->{config_version})) { | |
136 | $totem->{config_version} = $new_value if $new_value; | |
137 | return $totem->{config_version}; | |
b6973a89 TL |
138 | } |
139 | ||
140 | return undef if $noerr; | |
141 | ||
142 | die "invalid corosync config - unable to read version\n"; | |
143 | } | |
144 | ||
145 | # read only - use "rename corosync.conf.new corosync.conf" to write | |
146 | PVE::Cluster::cfs_register_file('corosync.conf', \&parse_conf); | |
147 | # this is read/write | |
148 | PVE::Cluster::cfs_register_file('corosync.conf.new', \&parse_conf, | |
149 | \&write_conf); | |
150 | ||
151 | sub check_conf_exists { | |
152 | my ($silent) = @_; | |
153 | ||
154 | $silent = $silent // 0; | |
155 | ||
156 | my $exists = -f "$basedir/corosync.conf"; | |
157 | ||
158 | warn "Corosync config '$basedir/corosync.conf' does not exist - is this node part of a cluster?\n" | |
159 | if !$silent && !$exists; | |
160 | ||
161 | return $exists; | |
162 | } | |
163 | ||
164 | sub update_nodelist { | |
165 | my ($conf, $nodelist) = @_; | |
166 | ||
167 | delete $conf->{digest}; | |
168 | ||
169 | my $version = conf_version($conf); | |
170 | conf_version($conf, undef, $version + 1); | |
171 | ||
e7ecad20 | 172 | $conf->{main}->{nodelist}->{node} = $nodelist; |
b6973a89 TL |
173 | |
174 | PVE::Cluster::cfs_write_file("corosync.conf.new", $conf); | |
175 | ||
176 | rename("/etc/pve/corosync.conf.new", "/etc/pve/corosync.conf") | |
177 | || die "activate corosync.conf.new failed - $!\n"; | |
178 | } | |
179 | ||
180 | sub nodelist { | |
181 | my ($conf) = @_; | |
e7ecad20 | 182 | return clone($conf->{main}->{nodelist}->{node}); |
b6973a89 TL |
183 | } |
184 | ||
b6973a89 TL |
185 | sub totem_config { |
186 | my ($conf) = @_; | |
e7ecad20 | 187 | return clone($conf->{main}->{totem}); |
b6973a89 TL |
188 | } |
189 | ||
190 | 1; |