From cafc7309facd1f3d2b1704122dcc58836f854068 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Thu, 26 Feb 2015 09:21:01 +0100 Subject: [PATCH] add parser for corosync.conf --- data/PVE/Cluster.pm | 263 +++++++++++++++++--------------------------- 1 file changed, 102 insertions(+), 161 deletions(-) diff --git a/data/PVE/Cluster.pm b/data/PVE/Cluster.pm index 5b67d05..e5e4a14 100644 --- a/data/PVE/Cluster.pm +++ b/data/PVE/Cluster.pm @@ -59,8 +59,8 @@ my $observed = { 'vzdump.cron' => 1, 'storage.cfg' => 1, 'datacenter.cfg' => 1, - 'cluster.conf' => 1, - 'cluster.conf.new' => 1, + 'corosync.conf' => 1, + 'corosync.conf.new' => 1, 'user.cfg' => 1, 'domains.cfg' => 1, 'priv/shadow.cfg' => 1, @@ -1292,195 +1292,136 @@ cfs_register_file('datacenter.cfg', \&parse_datacenter_config, \&write_datacenter_config); -sub parse_cluster_conf { +# a very simply parser ... +sub parse_corosync_conf { my ($filename, $raw) = @_; - my $conf = {}; + return {} if !$raw; my $digest = Digest::SHA::sha1_hex(defined($raw) ? $raw : ''); - my $createNode = sub { - my ($expat, $tag, %attrib) = @_; - $expat->{NodeCount}++; - return { text => $tag, id => $expat->{NodeCount}, %attrib }; - }; - - my $handlers = { - Init => sub { - my $expat = shift; - $expat->{NodeCount} = 0; - $expat->{NodeStack} = []; - $expat->{CurNode} = $expat->{Tree} = &$createNode($expat, 'root'); - }, - Final => sub { - my $expat = shift; - delete $expat->{CurNode}; - delete $expat->{NodeStack}; - $expat->{Tree}; - }, - Start => sub { - my $expat = shift; - my $tag = shift; - my $parent = $expat->{CurNode}; - push @{ $expat->{NodeStack} }, $parent; - my $node = &$createNode($expat, $tag, @_); - push @{$expat->{CurNode}->{children}}, $node; - $expat->{CurNode} = $node; - }, - End => sub { - my $expat = shift; - my $tag = shift; - my $node = pop @{ $expat->{NodeStack} }; - $expat->{CurNode} = $node; - }, - }; - - if ($raw) { - my $parser = new XML::Parser(Handlers => $handlers); - $conf = $parser->parse($raw); - } - - $conf->{digest} = $digest; - - return $conf; -} - -sub cluster_conf_version { - my ($conf, $noerr) = @_; + $raw =~ s/#.*$//mg; + $raw =~ s/\r?\n/ /g; + $raw =~ s/\s+/ /g; + $raw =~ s/^\s+//; + $raw =~ s/\s*$//; + + print "RAW: $raw\n"; + + my @tokens = split(/\s/, $raw); + + my $conf = { section => 'main', children => [] }; - if ($conf && $conf->{children} && $conf->{children}->[0]) { - my $cluster = $conf->{children}->[0]; - if ($cluster && ($cluster->{text} eq 'cluster') && - $cluster->{config_version}) { - if (my $version = int($cluster->{config_version})) { - return wantarray ? ($version, $cluster) : $version; - } + my $stack = []; + my $section = $conf; + + while (defined(my $token = shift @tokens)) { + my $nexttok = $tokens[0]; + + if ($nexttok && ($nexttok eq '{')) { + shift @tokens; # skip '{' + my $new_section = { + section => $token, + children => [], + }; + push @{$section->{children}}, $new_section; + push @$stack, $section; + $section = $new_section; + next; } - } - return undef if $noerr; + if ($token eq '}') { + $section = pop @$stack; + die "parse error - uncexpected '}'\n" if !$section; + next; + } - die "no cluster config - unable to read version\n"; -} + my $key = $token; + die "missing ':' after key '$key'\n" if ! ($key =~ s/:$//); + + die "parse error - no value for '$key'\n" if !defined($nexttok); + my $value = shift @tokens; -sub cluster_conf_lookup_cluster_section { - my ($conf, $noerr) = @_; + push @{$section->{children}}, { key => $key, value => $value }; + } - my ($version, $cluster) = cluster_conf_version($conf, $noerr); + $conf->{digest} = $digest; - return $cluster; + return $conf; } -sub cluster_conf_lookup_rm_section { - my ($conf, $create, $noerr) = @_; - - my $cluster = cluster_conf_lookup_cluster_section($conf, $noerr); - return undef if !$cluster; +my $dump_corosync_section; +$dump_corosync_section = sub { + my ($section, $prefix) = @_; - my $rmsec; - foreach my $child (@{$cluster->{children}}) { - if ($child->{text} eq 'rm') { - $rmsec = $child; - } + my $raw = $prefix . $section->{section} . " {\n"; + + my @list = grep { defined($_->{key}) } @{$section->{children}}; + foreach my $child (sort {$a->{key} cmp $b->{key}} @list) { + $raw .= $prefix . " $child->{key}: $child->{value}\n"; } - if (!$rmsec) { - if (!$create) { - return undef if $noerr; - die "no resource manager section\n"; - } - $rmsec = { text => 'rm' }; - push @{$cluster->{children}}, $rmsec; + + @list = grep { defined($_->{section}) } @{$section->{children}}; + foreach my $child (sort {$a->{section} cmp $b->{section}} @list) { + $raw .= &$dump_corosync_section($child, "$prefix "); } - return $rmsec; -} + $raw .= $prefix . "}\n\n"; + + return $raw; + +}; -sub cluster_conf_lookup_pvevm { - my ($conf, $create, $vmid, $noerr) = @_; +sub write_corosync_conf { + my ($filename, $conf) = @_; - my $rmsec = cluster_conf_lookup_rm_section($conf, $create, $noerr); - return undef if !$rmsec; + my $raw = ''; - my $vmref; - foreach my $child (@{$rmsec->{children}}) { - if ($child->{text} eq 'pvevm' && $child->{vmid} eq $vmid) { - $vmref = $child; - } - } + my $prefix = ''; + + die "no main section" if $conf->{section} ne 'main'; - if (!$vmref) { - if (!$create) { - return undef if $noerr; - die "unable to find service 'pvevm:$vmid'\n"; - } - $vmref = { text => 'pvevm', vmid => $vmid }; - push @{$rmsec->{children}}, $vmref; - } elsif ($create) { - return undef if $noerr; - die "unable to create service 'pvevm:$vmid' - already exists\n"; + my @list = grep { defined($_->{key}) } @{$conf->{children}}; + foreach my $child (sort {$a->{key} cmp $b->{key}} @list) { + $raw .= "$child->{key}: $child->{value}\n"; } - return $vmref; -} - -sub xml_escape_attrib { - my ($data) = @_; - - return '' if !defined($data); - - $data =~ s/&/&/sg; - $data =~ s//>/sg; - $data =~ s/"/"/sg; + @list = grep { defined($_->{section}) } @{$conf->{children}}; + foreach my $child (sort {$a->{section} cmp $b->{section}} @list) { + $raw .= &$dump_corosync_section($child, $prefix); + } - return $data; + return $raw; } -sub __cluster_conf_dump_node { - my ($node, $indend) = @_; - - my $xml = ''; - - $indend = '' if !defined($indend); - - my $attribs = ''; - - foreach my $key (sort keys %$node) { - my $value = $node->{$key}; - next if $key eq 'id' || $key eq 'text' || $key eq 'children'; - $attribs .= " $key=\"" . xml_escape_attrib($value) . "\""; - } - - my $children = $node->{children}; - - if ($children && scalar(@$children)) { - $xml .= "$indend<$node->{text}$attribs>\n"; - my $childindend = "$indend "; - foreach my $child (@$children) { - $xml .= __cluster_conf_dump_node($child, $childindend); +sub corosync_conf_version { + my ($conf, $noerr, $new_value) = @_; + + foreach my $child (@{$conf->{children}}) { + next if !defined($child->{section}); + if ($child->{section} eq 'totem') { + foreach my $e (@{$child->{children}}) { + next if !defined($e->{key}); + if ($e->{key} eq 'config_version') { + if ($new_value) { + $e->{value} = $new_value; + return $new_value; + } elsif (my $version = int($e->{value})) { + return $version; + } + last; + } + } } - $xml .= "$indend{text}>\n"; - } else { - $xml .= "$indend<$node->{text}$attribs/>\n"; } + + return undef if $noerr; - return $xml; -} - -sub write_cluster_conf { - my ($filename, $cfg) = @_; - - my $version = cluster_conf_version($cfg); - - my $res = "\n"; - - $res .= __cluster_conf_dump_node($cfg->{children}->[0]); - - return $res; + die "invalid corosync config - unable to read version\n"; } -# read only - use "rename cluster.conf.new cluster.conf" to write -PVE::Cluster::cfs_register_file('cluster.conf', \&parse_cluster_conf); +# read only - use "rename corosync.conf.new corosync.conf" to write +PVE::Cluster::cfs_register_file('corosync.conf', \&parse_corosync_conf); # this is read/write -PVE::Cluster::cfs_register_file('cluster.conf.new', \&parse_cluster_conf, - \&write_cluster_conf); +PVE::Cluster::cfs_register_file('corosync.conf.new', \&parse_corosync_conf, + \&write_corosync_conf); -- 2.39.5