[pve-devel] [PATCH cluster v2 1/2] factor out corosync methods to own module
Thomas Lamprecht
t.lamprecht at proxmox.com
Tue Jun 13 09:25:33 CEST 2017
PVE::Cluster is already quite big, the corosync part is ~250 lines
long of 1900 total. Further the corosync part is only needed in a few
specialised places (API2/ClusterConfig and CLI/pvecm).
This speaks for factoring out this part in a separate perl module as
most modules which use Cluster load the corosync parts for no reason.
Further, cluster handling through API may even add more corosync
related methods.
Create a new Corosync perl module and move all relevant methods over.
Method names lost the 'corosync_' prefix, not really needed anymore
as they already lives in the 'Corosync' namespace now.
Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
---
changes v1 -> v2:
* drop 'corosync_' part in methods part of PVE::Corosync
data/PVE/API2/ClusterConfig.pm | 6 +-
data/PVE/CLI/pvecm.pm | 17 +--
data/PVE/Cluster.pm | 245 ---------------------------------------
data/PVE/Corosync.pm | 257 +++++++++++++++++++++++++++++++++++++++++
data/PVE/Makefile.am | 2 +-
5 files changed, 271 insertions(+), 256 deletions(-)
create mode 100644 data/PVE/Corosync.pm
diff --git a/data/PVE/API2/ClusterConfig.pm b/data/PVE/API2/ClusterConfig.pm
index 65b376f..354b8ad 100644
--- a/data/PVE/API2/ClusterConfig.pm
+++ b/data/PVE/API2/ClusterConfig.pm
@@ -2,12 +2,14 @@ package PVE::API2::ClusterConfig;
use strict;
use warnings;
+
use PVE::Tools;
use PVE::SafeSyslog;
use PVE::RESTHandler;
use PVE::RPCEnvironment;
use PVE::JSONSchema qw(get_standard_option);
use PVE::Cluster;
+use PVE::Corosync;
use base qw(PVE::RESTHandler);
@@ -69,7 +71,7 @@ __PACKAGE__->register_method({
my $conf = PVE::Cluster::cfs_read_file('corosync.conf');
- my $nodelist = PVE::Cluster::corosync_nodelist($conf);
+ my $nodelist = PVE::Corosync::nodelist($conf);
return PVE::RESTHandler::hash_to_array($nodelist, 'node');
}});
@@ -96,7 +98,7 @@ __PACKAGE__->register_method({
my $conf = PVE::Cluster::cfs_read_file('corosync.conf');
- return PVE::Cluster::corosync_totem_config($conf);
+ return PVE::Corosync::totem_config($conf);
}});
1;
diff --git a/data/PVE/CLI/pvecm.pm b/data/PVE/CLI/pvecm.pm
index 6cd5084..c5622c5 100755
--- a/data/PVE/CLI/pvecm.pm
+++ b/data/PVE/CLI/pvecm.pm
@@ -16,6 +16,7 @@ use PVE::Cluster;
use PVE::INotify;
use PVE::JSONSchema;
use PVE::CLIHandler;
+use PVE::Corosync;
use base qw(PVE::CLIHandler);
@@ -312,9 +313,9 @@ __PACKAGE__->register_method ({
my $conf = PVE::Cluster::cfs_read_file("corosync.conf");
- my $nodelist = PVE::Cluster::corosync_nodelist($conf);
+ my $nodelist = PVE::Corosync::nodelist($conf);
- my $totem_cfg = PVE::Cluster::corosync_totem_config($conf);
+ my $totem_cfg = PVE::Corosync::totem_config($conf);
my $name = $param->{node};
@@ -390,7 +391,7 @@ __PACKAGE__->register_method ({
$nodelist->{$name}->{ring1_addr} = $param->{ring1_addr} if $param->{ring1_addr};
$nodelist->{$name}->{quorum_votes} = $param->{votes} if $param->{votes};
- PVE::Cluster::corosync_update_nodelist($conf, $nodelist);
+ PVE::Corosync::update_nodelist($conf, $nodelist);
exit (0);
}});
@@ -419,7 +420,7 @@ __PACKAGE__->register_method ({
my $conf = PVE::Cluster::cfs_read_file("corosync.conf");
- my $nodelist = PVE::Cluster::corosync_nodelist($conf);
+ my $nodelist = PVE::Corosync::nodelist($conf);
my $node;
my $nodeid;
@@ -442,7 +443,7 @@ __PACKAGE__->register_method ({
delete $nodelist->{$node};
- PVE::Cluster::corosync_update_nodelist($conf, $nodelist);
+ PVE::Corosync::update_nodelist($conf, $nodelist);
PVE::Tools::run_command(['corosync-cfgtool','-k', $nodeid])
if defined($nodeid);
@@ -674,7 +675,7 @@ __PACKAGE__->register_method ({
code => sub {
my ($param) = @_;
- PVE::Cluster::check_corosync_conf_exists();
+ PVE::Corosync::check_conf_exists();
my $cmd = ['corosync-quorumtool', '-siH'];
@@ -697,7 +698,7 @@ __PACKAGE__->register_method ({
code => sub {
my ($param) = @_;
- PVE::Cluster::check_corosync_conf_exists();
+ PVE::Corosync::check_conf_exists();
my $cmd = ['corosync-quorumtool', '-l'];
@@ -726,7 +727,7 @@ __PACKAGE__->register_method ({
code => sub {
my ($param) = @_;
- PVE::Cluster::check_corosync_conf_exists();
+ PVE::Corosync::check_conf_exists();
my $cmd = ['corosync-quorumtool', '-e', $param->{expected}];
diff --git a/data/PVE/Cluster.pm b/data/PVE/Cluster.pm
index 05897ed..9c8ce02 100644
--- a/data/PVE/Cluster.pm
+++ b/data/PVE/Cluster.pm
@@ -1433,251 +1433,6 @@ cfs_register_file('datacenter.cfg',
\&parse_datacenter_config,
\&write_datacenter_config);
-# a very simply parser ...
-sub parse_corosync_conf {
- my ($filename, $raw) = @_;
-
- return {} if !$raw;
-
- my $digest = Digest::SHA::sha1_hex(defined($raw) ? $raw : '');
-
- $raw =~ s/#.*$//mg;
- $raw =~ s/\r?\n/ /g;
- $raw =~ s/\s+/ /g;
- $raw =~ s/^\s+//;
- $raw =~ s/\s*$//;
-
- my @tokens = split(/\s/, $raw);
-
- my $conf = { section => 'main', children => [] };
-
- 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;
- }
-
- if ($token eq '}') {
- $section = pop @$stack;
- die "parse error - uncexpected '}'\n" if !$section;
- next;
- }
-
- 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;
-
- push @{$section->{children}}, { key => $key, value => $value };
- }
-
- $conf->{digest} = $digest;
-
- return $conf;
-}
-
-my $dump_corosync_section;
-$dump_corosync_section = sub {
- my ($section, $prefix) = @_;
-
- 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";
- }
-
- @list = grep { defined($_->{section}) } @{$section->{children}};
- foreach my $child (sort {$a->{section} cmp $b->{section}} @list) {
- $raw .= &$dump_corosync_section($child, "$prefix ");
- }
-
- $raw .= $prefix . "}\n\n";
-
- return $raw;
-
-};
-
-sub write_corosync_conf {
- my ($filename, $conf) = @_;
-
- my $raw = '';
-
- my $prefix = '';
-
- die "no main section" if $conf->{section} ne 'main';
-
- my @list = grep { defined($_->{key}) } @{$conf->{children}};
- foreach my $child (sort {$a->{key} cmp $b->{key}} @list) {
- $raw .= "$child->{key}: $child->{value}\n";
- }
-
- @list = grep { defined($_->{section}) } @{$conf->{children}};
- foreach my $child (sort {$a->{section} cmp $b->{section}} @list) {
- $raw .= &$dump_corosync_section($child, $prefix);
- }
-
- return $raw;
-}
-
-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;
- }
- }
- }
- }
-
- return undef if $noerr;
-
- die "invalid corosync config - unable to read version\n";
-}
-
-# 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('corosync.conf.new', \&parse_corosync_conf,
- \&write_corosync_conf);
-
-sub check_corosync_conf_exists {
- my ($silent) = @_;
-
- $silent = $silent // 0;
-
- my $exists = -f "$basedir/corosync.conf";
-
- warn "Corosync config '$basedir/corosync.conf' does not exist - is this node part of a cluster?\n"
- if !$silent && !$exists;
-
- return $exists;
-}
-
-sub corosync_update_nodelist {
- my ($conf, $nodelist) = @_;
-
- delete $conf->{digest};
-
- my $version = corosync_conf_version($conf);
- corosync_conf_version($conf, undef, $version + 1);
-
- my $children = [];
- foreach my $v (values %$nodelist) {
- next if !($v->{ring0_addr} || $v->{name});
- my $kv = [];
- foreach my $k (keys %$v) {
- push @$kv, { key => $k, value => $v->{$k} };
- }
- my $ns = { section => 'node', children => $kv };
- push @$children, $ns;
- }
-
- foreach my $main (@{$conf->{children}}) {
- next if !defined($main->{section});
- if ($main->{section} eq 'nodelist') {
- $main->{children} = $children;
- last;
- }
- }
-
-
- cfs_write_file("corosync.conf.new", $conf);
-
- rename("/etc/pve/corosync.conf.new", "/etc/pve/corosync.conf")
- || die "activate corosync.conf.new failed - $!\n";
-}
-
-sub corosync_nodelist {
- my ($conf) = @_;
-
- my $nodelist = {};
-
- foreach my $main (@{$conf->{children}}) {
- next if !defined($main->{section});
- if ($main->{section} eq 'nodelist') {
- foreach my $ne (@{$main->{children}}) {
- next if !defined($ne->{section}) || ($ne->{section} ne 'node');
- my $node = { quorum_votes => 1 };
- my $name;
- foreach my $child (@{$ne->{children}}) {
- next if !defined($child->{key});
- $node->{$child->{key}} = $child->{value};
- # use 'name' over 'ring0_addr' if set
- if ($child->{key} eq 'name') {
- delete $nodelist->{$name} if $name;
- $name = $child->{value};
- $nodelist->{$name} = $node;
- } elsif(!$name && $child->{key} eq 'ring0_addr') {
- $name = $child->{value};
- $nodelist->{$name} = $node;
- }
- }
- }
- }
- }
-
- return $nodelist;
-}
-
-# get a hash representation of the corosync config totem section
-sub corosync_totem_config {
- my ($conf) = @_;
-
- my $res = {};
-
- foreach my $main (@{$conf->{children}}) {
- next if !defined($main->{section}) ||
- $main->{section} ne 'totem';
-
- foreach my $e (@{$main->{children}}) {
-
- if ($e->{section} && $e->{section} eq 'interface') {
- my $entry = {};
-
- $res->{interface} = {};
-
- foreach my $child (@{$e->{children}}) {
- next if !defined($child->{key});
- $entry->{$child->{key}} = $child->{value};
- if($child->{key} eq 'ringnumber') {
- $res->{interface}->{$child->{value}} = $entry;
- }
- }
-
- } elsif ($e->{key}) {
- $res->{$e->{key}} = $e->{value};
- }
- }
- }
-
- return $res;
-}
-
# X509 Certificate cache helper
my $cert_cache_nodes = {};
diff --git a/data/PVE/Corosync.pm b/data/PVE/Corosync.pm
new file mode 100644
index 0000000..59b813e
--- /dev/null
+++ b/data/PVE/Corosync.pm
@@ -0,0 +1,257 @@
+package PVE::Corosync;
+
+use strict;
+use warnings;
+
+use Digest::SHA;
+
+use PVE::Cluster;
+
+my $basedir = "/etc/pve";
+
+# a very simply parser ...
+sub parse_conf {
+ my ($filename, $raw) = @_;
+
+ return {} if !$raw;
+
+ my $digest = Digest::SHA::sha1_hex(defined($raw) ? $raw : '');
+
+ $raw =~ s/#.*$//mg;
+ $raw =~ s/\r?\n/ /g;
+ $raw =~ s/\s+/ /g;
+ $raw =~ s/^\s+//;
+ $raw =~ s/\s*$//;
+
+ my @tokens = split(/\s/, $raw);
+
+ my $conf = { section => 'main', children => [] };
+
+ 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;
+ }
+
+ if ($token eq '}') {
+ $section = pop @$stack;
+ die "parse error - uncexpected '}'\n" if !$section;
+ next;
+ }
+
+ 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;
+
+ push @{$section->{children}}, { key => $key, value => $value };
+ }
+
+ $conf->{digest} = $digest;
+
+ return $conf;
+}
+
+my $dump_section;
+$dump_section = sub {
+ my ($section, $prefix) = @_;
+
+ 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";
+ }
+
+ @list = grep { defined($_->{section}) } @{$section->{children}};
+ foreach my $child (sort {$a->{section} cmp $b->{section}} @list) {
+ $raw .= &$dump_section($child, "$prefix ");
+ }
+
+ $raw .= $prefix . "}\n\n";
+
+ return $raw;
+
+};
+
+sub write_conf {
+ my ($filename, $conf) = @_;
+
+ my $raw = '';
+
+ my $prefix = '';
+
+ die "no main section" if $conf->{section} ne 'main';
+
+ my @list = grep { defined($_->{key}) } @{$conf->{children}};
+ foreach my $child (sort {$a->{key} cmp $b->{key}} @list) {
+ $raw .= "$child->{key}: $child->{value}\n";
+ }
+
+ @list = grep { defined($_->{section}) } @{$conf->{children}};
+ foreach my $child (sort {$a->{section} cmp $b->{section}} @list) {
+ $raw .= &$dump_section($child, $prefix);
+ }
+
+ return $raw;
+}
+
+sub 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;
+ }
+ }
+ }
+ }
+
+ return undef if $noerr;
+
+ die "invalid corosync config - unable to read version\n";
+}
+
+# read only - use "rename corosync.conf.new corosync.conf" to write
+PVE::Cluster::cfs_register_file('corosync.conf', \&parse_conf);
+# this is read/write
+PVE::Cluster::cfs_register_file('corosync.conf.new', \&parse_conf,
+ \&write_conf);
+
+sub check_conf_exists {
+ my ($silent) = @_;
+
+ $silent = $silent // 0;
+
+ my $exists = -f "$basedir/corosync.conf";
+
+ warn "Corosync config '$basedir/corosync.conf' does not exist - is this node part of a cluster?\n"
+ if !$silent && !$exists;
+
+ return $exists;
+}
+
+sub update_nodelist {
+ my ($conf, $nodelist) = @_;
+
+ delete $conf->{digest};
+
+ my $version = conf_version($conf);
+ conf_version($conf, undef, $version + 1);
+
+ my $children = [];
+ foreach my $v (values %$nodelist) {
+ next if !($v->{ring0_addr} || $v->{name});
+ my $kv = [];
+ foreach my $k (keys %$v) {
+ push @$kv, { key => $k, value => $v->{$k} };
+ }
+ my $ns = { section => 'node', children => $kv };
+ push @$children, $ns;
+ }
+
+ foreach my $main (@{$conf->{children}}) {
+ next if !defined($main->{section});
+ if ($main->{section} eq 'nodelist') {
+ $main->{children} = $children;
+ last;
+ }
+ }
+
+
+ PVE::Cluster::cfs_write_file("corosync.conf.new", $conf);
+
+ rename("/etc/pve/corosync.conf.new", "/etc/pve/corosync.conf")
+ || die "activate corosync.conf.new failed - $!\n";
+}
+
+sub nodelist {
+ my ($conf) = @_;
+
+ my $nodelist = {};
+
+ foreach my $main (@{$conf->{children}}) {
+ next if !defined($main->{section});
+ if ($main->{section} eq 'nodelist') {
+ foreach my $ne (@{$main->{children}}) {
+ next if !defined($ne->{section}) || ($ne->{section} ne 'node');
+ my $node = { quorum_votes => 1 };
+ my $name;
+ foreach my $child (@{$ne->{children}}) {
+ next if !defined($child->{key});
+ $node->{$child->{key}} = $child->{value};
+ # use 'name' over 'ring0_addr' if set
+ if ($child->{key} eq 'name') {
+ delete $nodelist->{$name} if $name;
+ $name = $child->{value};
+ $nodelist->{$name} = $node;
+ } elsif(!$name && $child->{key} eq 'ring0_addr') {
+ $name = $child->{value};
+ $nodelist->{$name} = $node;
+ }
+ }
+ }
+ }
+ }
+
+ return $nodelist;
+}
+
+# get a hash representation of the corosync config totem section
+sub totem_config {
+ my ($conf) = @_;
+
+ my $res = {};
+
+ foreach my $main (@{$conf->{children}}) {
+ next if !defined($main->{section}) ||
+ $main->{section} ne 'totem';
+
+ foreach my $e (@{$main->{children}}) {
+
+ if ($e->{section} && $e->{section} eq 'interface') {
+ my $entry = {};
+
+ $res->{interface} = {};
+
+ foreach my $child (@{$e->{children}}) {
+ next if !defined($child->{key});
+ $entry->{$child->{key}} = $child->{value};
+ if($child->{key} eq 'ringnumber') {
+ $res->{interface}->{$child->{value}} = $entry;
+ }
+ }
+
+ } elsif ($e->{key}) {
+ $res->{$e->{key}} = $e->{value};
+ }
+ }
+ }
+
+ return $res;
+}
+
+1;
diff --git a/data/PVE/Makefile.am b/data/PVE/Makefile.am
index 6a38431..1f576b0 100644
--- a/data/PVE/Makefile.am
+++ b/data/PVE/Makefile.am
@@ -25,7 +25,7 @@ man5_MANS = datacenter.cfg.5
IPCC_so_SOURCES = IPCC.c ppport.h
-pvelib_DATA = IPCC.pm Cluster.pm
+pvelib_DATA = IPCC.pm Cluster.pm Corosync.pm
pvelibdir = $(PERL_VENDORLIB)/PVE
noinst_DATA = pvecm.bash-completion
--
2.11.0
More information about the pve-devel
mailing list