]> git.proxmox.com Git - pve-cluster.git/commitdiff
api/cluster: add join endpoint
authorThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 27 Nov 2017 09:55:14 +0000 (10:55 +0100)
committerFabian Grünbichler <f.gruenbichler@proxmox.com>
Fri, 16 Feb 2018 12:50:36 +0000 (13:50 +0100)
Add an endpoint to the API which allows to join an existing PVE
cluster by only using the API instead of CLI tools (pvecm).

Use a worker as this operation may need longer than 30 seconds.
With the worker we also get a task log entry/window for an UI for
free, allowing to give better feedback.

The join helper will be reused by the CLI handler in a later patch.
It is based on its behaviour, but swapped out the ssh parts with API
calls.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
data/PVE/API2/ClusterConfig.pm
data/PVE/Cluster.pm
debian/control.in

index 5bdf9707b91376c2774cb57a0b3e900921125126..6b2f6c172644f8ce0572bfb8fdec5ec05e1956fa 100644 (file)
@@ -9,6 +9,7 @@ use PVE::RESTHandler;
 use PVE::RPCEnvironment;
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::Cluster;
+use PVE::APIClient::LWP;
 use PVE::Corosync;
 
 use base qw(PVE::RESTHandler);
@@ -39,7 +40,8 @@ __PACKAGE__->register_method({
        my $result = [
            { name => 'nodes' },
            { name => 'totem' },
-           ];
+           { name => 'join' },
+       ];
 
        return $result;
     }});
@@ -94,7 +96,6 @@ my $config_change_lock = sub {
     });
 };
 
-
 __PACKAGE__->register_method ({
     name => 'addnode',
     path => 'nodes/{node}',
@@ -305,6 +306,71 @@ __PACKAGE__->register_method ({
        return undef;
     }});
 
+__PACKAGE__->register_method ({
+    name => 'join',
+    path => 'join',
+    method => 'POST',
+    protected => 1,
+    description => "Joins this node into an existing cluster.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           hostname => {
+               type => 'string',
+               description => "Hostname (or IP) of an existing cluster member."
+           },
+           nodeid => {
+               type => 'integer',
+               description => "Node id for this node.",
+               minimum => 1,
+               optional => 1,
+           },
+           votes => {
+               type => 'integer',
+               description => "Number of votes for this node",
+               minimum => 0,
+               optional => 1,
+           },
+           force => {
+               type => 'boolean',
+               description => "Do not throw error if node already exists.",
+               optional => 1,
+           },
+           ring0_addr => {
+               type => 'string', format => 'address',
+               description => "Hostname (or IP) of the corosync ring0 address of this node.".
+                   " Defaults to nodes hostname.",
+               optional => 1,
+           },
+           ring1_addr => {
+               type => 'string', format => 'address',
+               description => "Hostname (or IP) of the corosync ring1 address, this".
+                   " needs an valid configured ring 1 interface in the cluster.",
+               optional => 1,
+           },
+           fingerprint => get_standard_option('fingerprint-sha256'),
+           password => {
+               description => "Superuser (root) password of peer node.",
+               type => 'string',
+               maxLength => 128,
+           },
+       },
+    },
+    returns => { type => 'string' },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+       my $authuser = $rpcenv->get_user();
+
+       my $worker = sub {
+           PVE::Cluster::join($param);
+       };
+
+       return $rpcenv->fork_worker('clusterjoin', '',  $authuser, $worker);
+    }});
+
+
 __PACKAGE__->register_method({
     name => 'totem',
     path => 'totem',
index c3677f47773c6f2851b4f3bf9d31ab5f08210503..c515fa974cecb48509740be928c990f4712aaa51 100644 (file)
@@ -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) = @_;
 
index e6ccc902fddaabd2a470aa669f58d14da936745d..1699be6816ab4e63555d0214077f050184a990cc 100644 (file)
@@ -21,6 +21,7 @@ Build-Depends: debhelper (>= 7),
                libdigest-hmac-perl,
                dh-systemd,
                pve-doc-generator,
+               libpve-apiclient-perl,
                libuuid-perl
 Standards-Version: 3.7.3
 
@@ -35,7 +36,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, @PERLAPI@,
          fuse,
          corosync (>= 2.3.4-1),
          libqb0 (>= 0.17.1-1),
-         libpve-common-perl,
+         libpve-common-perl (>= 5.0-27),
          libglib2.0-0 (>= 2.42.1-1),
          rsyslog,
          openssl,
@@ -47,6 +48,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, @PERLAPI@,
          faketime,
          libcrypt-ssleay-perl,
          libuuid-perl,
+         libpve-apiclient-perl,
          lsb-base
 Breaks: pve-ha-manager (<<2.0-4)
 Description: Cluster Infrastructure for Proxmox Virtual Environment