]> git.proxmox.com Git - pve-cluster.git/commitdiff
factor out corosync methods to own module
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Tue, 13 Jun 2017 07:25:33 +0000 (09:25 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Wed, 21 Jun 2017 05:37:12 +0000 (07:37 +0200)
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@proxmox.com>
data/PVE/API2/ClusterConfig.pm
data/PVE/CLI/pvecm.pm
data/PVE/Cluster.pm
data/PVE/Corosync.pm [new file with mode: 0644]
data/PVE/Makefile.am

index 65b376f11b77963c1cc3e87035cd5a828193910b..354b8adf90dd28fd1d4c36cee3b09b699aac94c6 100644 (file)
@@ -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;
index 6cd5084417cd213bbd8e628cae01d691095e515c..c5622c5d1b879a6c7faf1d64d7d8de9b2a85e04e 100755 (executable)
@@ -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}];
 
index 05897ed69e19fad228aec5f6a2983513e832143c..9c8ce022ae94c67d9d313f0e1dad0ab0908506f6 100644 (file)
@@ -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 (file)
index 0000000..59b813e
--- /dev/null
@@ -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;
index 6a38431ed9a6ce3384f44b3f8b7ee151b62c5398..1f576b0553ad2cab24a969b7f841af754d7fe703 100644 (file)
@@ -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