Factor out common code, which will be used by the new API endpoint to
join a cluster and the old legacy SSH method which we will keep for a
bit.

Signed-off-by: Thomas Lamprecht <t.lampre...@proxmox.com>
---
 data/PVE/CLI/pvecm.pm | 152 ++------------------------------------------------
 data/PVE/Cluster.pm   | 146 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+), 147 deletions(-)

diff --git a/data/PVE/CLI/pvecm.pm b/data/PVE/CLI/pvecm.pm
index 4028e42..e76a822 100755
--- a/data/PVE/CLI/pvecm.pm
+++ b/data/PVE/CLI/pvecm.pm
@@ -25,40 +25,6 @@ my $backupdir = "/var/lib/pve-cluster/backup";
 my $dbfile = "$libdir/config.db";
 my $authfile = "/etc/corosync/authkey";
 
-sub backup_database {
-
-    print "backup old database\n";
-
-    mkdir $backupdir;
-
-    my $ctime = time();
-    my $cmd = [
-       ['echo', '.dump'],
-       ['sqlite3', $dbfile],
-       ['gzip', '-', \ ">${backupdir}/config-${ctime}.sql.gz"],
-    ];
-
-    run_command($cmd, 'errmsg' => "cannot backup old database\n");
-
-    # purge older backup
-    my $maxfiles = 10;
-
-    my @bklist = ();
-    foreach my $fn (<$backupdir/config-*.sql.gz>) {
-       if ($fn =~ m!/config-(\d+)\.sql.gz$!) {
-           push @bklist, [$fn, $1];
-       }
-    }
-
-    @bklist = sort { $b->[1] <=> $a->[1] } @bklist;
-
-    while (scalar (@bklist) >= $maxfiles) {
-       my $d = pop @bklist;
-       print "delete old backup '$d->[0]'\n";
-       unlink $d->[0];
-    }
-}
-
 
 __PACKAGE__->register_method ({
     name => 'keygen',
@@ -308,67 +274,10 @@ __PACKAGE__->register_method ({
        PVE::Cluster::setup_rootsshconfig();
        PVE::Cluster::setup_ssh_keys();
 
+       PVE::Cluster::assert_joinable($param->{ring0_addr}, 
$param->{ring1_addr}, $param->{force});
+
        my $host = $param->{hostname};
 
-       my ($errors, $warnings) = ('', '');
-
-       my $error = sub {
-           my ($msg, $suppress) = @_;
-
-           if ($suppress) {
-               $warnings .= "* $msg\n";
-           } else {
-               $errors .= "* $msg\n";
-           }
-       };
-
-       if (!$param->{force}) {
-
-           if (-f $authfile) {
-               &$error("authentication key '$authfile' already exists", 
$param->{force});
-           }
-
-           if (-f $clusterconf)  {
-               &$error("cluster config '$clusterconf' already exists", 
$param->{force});
-           }
-
-           my $vmlist = PVE::Cluster::get_vmlist();
-           if ($vmlist && $vmlist->{ids} && scalar(keys %{$vmlist->{ids}})) {
-               &$error("this host already contains virtual guests", 
$param->{force});
-           }
-
-           if (system("corosync-quorumtool -l >/dev/null 2>&1") == 0) {
-               &$error("corosync is already running, is this node already in a 
cluster?!", $param->{force});
-           }
-       }
-
-       # check if corosync ring IPs are configured on the current nodes 
interfaces
-       my $check_ip = sub {
-           my $ip = shift;
-           if (defined($ip)) {
-               if (!PVE::JSONSchema::pve_verify_ip($ip, 1)) {
-                   my $host = $ip;
-                   eval { $ip = PVE::Network::get_ip_from_hostname($host); };
-                   if ($@) {
-                       &$error("cannot use '$host': $@\n") ;
-                       return;
-                   }
-               }
-
-               my $cidr = (Net::IP::ip_is_ipv6($ip)) ? "$ip/128" : "$ip/32";
-               my $configured_ips = 
PVE::Network::get_local_ip_from_cidr($cidr);
-
-               &$error("cannot use IP '$ip', it must be configured exactly 
once on local node!\n")
-                   if (scalar(@$configured_ips) != 1);
-           }
-       };
-
-       &$check_ip($param->{ring0_addr});
-       &$check_ip($param->{ring1_addr});
-
-       warn "warning, ignore the following errors:\n$warnings" if $warnings;
-       die "detected the following error(s):\n$errors" if $errors;
-
        # make sure known_hosts is on local filesystem
        PVE::Cluster::ssh_unmerge_known_hosts();
 
@@ -380,11 +289,8 @@ __PACKAGE__->register_method ({
                'pvecm', 'addnode', $nodename, '--force', 1];
 
        push @$cmd, '--nodeid', $param->{nodeid} if $param->{nodeid};
-
        push @$cmd, '--votes', $param->{votes} if defined($param->{votes});
-
        push @$cmd, '--ring0_addr', $param->{ring0_addr} if 
defined($param->{ring0_addr});
-
        push @$cmd, '--ring1_addr', $param->{ring1_addr} if 
defined($param->{ring1_addr});
 
        if (system (@$cmd) != 0) {
@@ -402,58 +308,10 @@ __PACKAGE__->register_method ({
 
            system(@$cmd) == 0 || die "can't rsync data from host '$host'\n";
 
-           mkdir "/etc/corosync";
-           my $confbase = basename($clusterconf);
+           my $corosync_conf = 
PVE::Tools::file_get_contents("$tmpdir/corosync.conf");
+           my $corosync_authkey = 
PVE::Tools::file_get_contents("$tmpdir/authkey");
 
-           $cmd = "cp '$tmpdir/$confbase' '/etc/corosync/$confbase'";
-           system($cmd) == 0 || die "can't copy cluster configuration\n";
-
-           my $keybase = basename($authfile);
-           system ("cp '$tmpdir/$keybase' '$authfile'") == 0 ||
-               die "can't copy '$tmpdir/$keybase' to '$authfile'\n";
-
-           print "stopping pve-cluster service\n";
-
-           system("umount $basedir -f >/dev/null 2>&1");
-           system("systemctl stop pve-cluster") == 0 ||
-               die "can't stop pve-cluster service\n";
-
-           backup_database();
-
-           unlink $dbfile;
-
-           system("systemctl start pve-cluster") == 0 ||
-               die "starting pve-cluster failed\n";
-
-           system("systemctl start corosync");
-
-           # wait for quorum
-           my $printqmsg = 1;
-           while (!PVE::Cluster::check_cfs_quorum(1)) {
-               if ($printqmsg) {
-                   print "waiting for quorum...";
-                   STDOUT->flush();
-                   $printqmsg = 0;
-               }
-               sleep(1);
-           }
-           print "OK\n" if !$printqmsg;
-
-           my $local_ip_address = PVE::Cluster::remote_node_ip($nodename);
-
-           print "generating node certificates\n";
-           PVE::Cluster::gen_pve_node_files($nodename, $local_ip_address);
-
-           print "merge known_hosts file\n";
-           PVE::Cluster::ssh_merge_known_hosts($nodename, $local_ip_address, 
1);
-
-           print "restart services\n";
-           # restart pvedaemon (changed certs)
-           system("systemctl restart pvedaemon");
-           # restart pveproxy (changed certs)
-           system("systemctl restart pveproxy");
-
-           print "successfully added node '$nodename' to cluster.\n";
+           PVE::Cluster::finish_join($host, $corosync_conf, $corosync_authkey);
        };
        my $err = $@;
 
diff --git a/data/PVE/Cluster.pm b/data/PVE/Cluster.pm
index 9a248ed..531a19d 100644
--- a/data/PVE/Cluster.pm
+++ b/data/PVE/Cluster.pm
@@ -1669,4 +1669,150 @@ sub ssh_info_to_command {
     return $cmd;
 }
 
+sub assert_joinable {
+    my ($ring0_addr, $ring1_addr, $force) = @_;
+
+    my $clusterconf = "/etc/pve/corosync.conf";
+    my $authfile = "/etc/corosync/authkey";
+
+    my ($errors, $warnings) = ('', '');
+    my $error = sub {
+       my ($msg, $suppress) = @_;
+
+       if ($suppress) {
+           $warnings .= "* $msg\n";
+       } else {
+           $errors .= "* $msg\n";
+       }
+    };
+
+    if (-f $authfile) {
+       $error->("authentication key '$authfile' already exists", $force);
+    }
+
+    if (-f $clusterconf)  {
+       $error->("cluster config '$clusterconf' already exists", $force);
+    }
+
+    my $vmlist = PVE::Cluster::get_vmlist();
+    if ($vmlist && $vmlist->{ids} && scalar(keys %{$vmlist->{ids}})) {
+       $error->("this host already contains virtual guests", $force);
+    }
+
+    if (system("corosync-quorumtool -l >/dev/null 2>&1") == 0) {
+       $error->("corosync is already running, is this node already in a 
cluster?!", $force);
+    }
+
+    # check if corosync ring IPs are configured on the current nodes interfaces
+    my $check_ip = sub {
+       my $ip = shift // return;
+       if (!PVE::JSONSchema::pve_verify_ip($ip, 1)) {
+           my $host = $ip;
+           eval { $ip = PVE::Network::get_ip_from_hostname($host); };
+           if ($@) {
+               $error->("cannot use '$host': $@\n", 1) ;
+               return;
+           }
+       }
+
+       my $cidr = (Net::IP::ip_is_ipv6($ip)) ? "$ip/128" : "$ip/32";
+       my $configured_ips = PVE::Network::get_local_ip_from_cidr($cidr);
+
+       $error->("cannot use IP '$ip', it must be configured exactly once on 
local node!\n")
+           if (scalar(@$configured_ips) != 1);
+    };
+
+    $check_ip->($ring0_addr);
+    $check_ip->($ring1_addr);
+
+    warn "warning, ignore the following errors:\n$warnings" if $warnings;
+    die "detected the following error(s):\n$errors" if $errors;
+}
+
+my $backup_cfs_database = sub {
+    my ($dbfile) = @_;
+
+    print "backup old database\n";
+
+    my $backupdir = "/var/lib/pve-cluster/backup";
+    mkdir $backupdir;
+
+    my $ctime = time();
+    my $cmd = [
+       ['echo', '.dump'],
+       ['sqlite3', $dbfile],
+       ['gzip', '-', \ ">${backupdir}/config-${ctime}.sql.gz"],
+    ];
+
+    PVE::Tools::run_command($cmd, 'errmsg' => "cannot backup old database\n");
+
+    # purge older backup
+    my $maxfiles = 10;
+
+    my @bklist = ();
+    foreach my $fn (<$backupdir/config-*.sql.gz>) {
+       if ($fn =~ m!/config-(\d+)\.sql.gz$!) {
+           push @bklist, [$fn, $1];
+       }
+    }
+
+    @bklist = sort { $b->[1] <=> $a->[1] } @bklist;
+
+    while (scalar (@bklist) >= $maxfiles) {
+       my $d = pop @bklist;
+       print "delete old backup '$d->[0]'\n";
+       unlink $d->[0];
+    }
+};
+
+sub finish_join {
+    my ($nodename, $corosync_conf, $corosync_authkey) = @_;
+
+    my $dbfile = "/var/lib/pve-cluster/config.db";
+    my $localclusterconf = "/etc/corosync/corosync.conf";
+    my $authfile = "/etc/corosync/authkey";
+
+    mkdir "/etc/corosync";
+    PVE::Tools::file_set_contents($authfile, $corosync_authkey);
+    PVE::Tools::file_set_contents($localclusterconf, $corosync_conf);
+
+    print "stopping pve-cluster service\n";
+
+    system("umount $basedir -f >/dev/null 2>&1");
+    die "can't stop pve-cluster service\n" if system("systemctl stop 
pve-cluster") != 0;
+
+    $backup_cfs_database->($dbfile);
+    unlink $dbfile;
+
+    system("systemctl start pve-cluster") == 0 || die "starting pve-cluster 
failed\n";
+    system("systemctl start corosync");
+
+    # wait for quorum
+    my $printqmsg = 1;
+    while (!PVE::Cluster::check_cfs_quorum(1)) {
+       if ($printqmsg) {
+           print "waiting for quorum...";
+           STDOUT->flush();
+           $printqmsg = 0;
+       }
+       sleep(1);
+    }
+    print "OK\n" if !$printqmsg;
+
+    my $local_ip_address = PVE::Cluster::remote_node_ip($nodename);
+
+    print "generating node certificates\n";
+    PVE::Cluster::gen_pve_node_files($nodename, $local_ip_address);
+
+    print "merge known_hosts file\n";
+    PVE::Cluster::ssh_merge_known_hosts($nodename, $local_ip_address, 1);
+
+    print "restart services\n";
+    # restart pvedaemon and pveproxy (changed certs)
+    system("systemctl restart pvedaemon pveproxy");
+
+    print "successfully added node '$nodename' to cluster.\n";
+}
+
+
 1;
-- 
2.11.0


_______________________________________________
pve-devel mailing list
pve-devel@pve.proxmox.com
https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to