]> git.proxmox.com Git - pve-cluster.git/blobdiff - data/PVE/Cluster.pm
api/cluster: add join endpoint
[pve-cluster.git] / data / PVE / Cluster.pm
index c2ea1ccc2c79f2f1fe8a05e028537867ce07cc3b..c515fa974cecb48509740be928c990f4712aaa51 100644 (file)
@@ -11,7 +11,7 @@ use MIME::Base64;
 use Digest::SHA;
 use Digest::HMAC_SHA1;
 use Net::SSLeay;
-use PVE::Tools;
+use PVE::Tools qw(run_command);
 use PVE::INotify;
 use PVE::IPCC;
 use PVE::SafeSyslog;
@@ -1711,7 +1711,7 @@ sub assert_joinable {
        $error->("this host already contains virtual guests");
     }
 
-    if (system("corosync-quorumtool -l >/dev/null 2>&1") == 0) {
+    if (run_command(['corosync-quorumtool', '-l'], noerr => 1, quiet => 1) == 0) {
        $error->("corosync is already running, is this node already in a cluster?!");
     }
 
@@ -1775,6 +1775,64 @@ my $backup_cfs_database = sub {
     }
 };
 
+sub join {
+    my ($param) = @_;
+
+    my $nodename = PVE::INotify::nodename();
+
+    setup_sshd_config();
+    setup_rootsshconfig();
+    setup_ssh_keys();
+
+    # check if we can join with the given parameters and current node state
+    my ($ring0_addr, $ring1_addr) = $param->@{'ring0_addr', 'ring1_addr'};
+    assert_joinable($ring0_addr, $ring1_addr, $param->{force});
+
+    # make sure known_hosts is on local filesystem
+    ssh_unmerge_known_hosts();
+
+    my $host = $param->{hostname};
+
+    my $conn_args = {
+       username => 'root@pam',
+       password => $param->{password},
+       cookie_name => 'PVEAuthCookie',
+       protocol => 'https',
+       host => $host,
+       port => 8006,
+    };
+
+    if (my $fp = $param->{fingerprint}) {
+       $conn_args->{cached_fingerprints} = { uc($fp) => 1 };
+    } else {
+       # API schema ensures that we can only get here from CLI handler
+       $conn_args->{manual_verification} = 1;
+    }
+
+    print "Etablishing API connection with host '$host'\n";
+
+    my $conn = PVE::APIClient::LWP->new(%$conn_args);
+    $conn->login();
+
+    # login raises an exception on failure, so if we get here we're good
+    print "Login succeeded.\n";
+
+    my $args = {};
+    $args->{force} = $param->{force} if defined($param->{force});
+    $args->{nodeid} = $param->{nodeid} if $param->{nodeid};
+    $args->{votes} = $param->{votes} if defined($param->{votes});
+    $args->{ring0_addr} = $ring0_addr if defined($ring0_addr);
+    $args->{ring1_addr} = $ring1_addr if defined($ring1_addr);
+
+    print "Request addition of this node\n";
+    my $res = $conn->post("/cluster/config/nodes/$nodename", $args);
+
+    print "Join request OK, finishing setup locally\n";
+
+    # added successfuly - now prepare local node
+    finish_join($nodename, $res->{corosync_conf}, $res->{corosync_authkey});
+}
+
 sub finish_join {
     my ($nodename, $corosync_conf, $corosync_authkey) = @_;
 
@@ -1783,15 +1841,14 @@ sub finish_join {
     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;
+    my $cmd = ['systemctl', 'stop', 'pve-cluster'];
+    run_command($cmd, errmsg => "can't stop pve-cluster service");
 
     $backup_cfs_database->($dbfile);
     unlink $dbfile;
 
-    system("systemctl start pve-cluster") == 0 || die "starting pve-cluster failed\n";
-    system("systemctl start corosync");
+    $cmd = ['systemctl', 'start', 'corosync', 'pve-cluster'];
+    run_command($cmd, errmsg => "starting pve-cluster failed");
 
     # wait for quorum
     my $printqmsg = 1;
@@ -1813,9 +1870,8 @@ sub finish_join {
     print "merge known_hosts file\n";
     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 "node certificate changed, restart pveproxy and pvedaemon services\n";
+    run_command(['systemctl', 'reload-or-restart', 'pvedaemon', 'pveproxy']);
 
     print "successfully added node '$nodename' to cluster.\n";
 }