Same as we do in assert_joinable, a cluster with unconfigured IPs will fail start after creation anyway.
Make "check_ip" a standalone sub ("check_ip_configured") and improve error messages all around. Also move call to create_conf up, so if it fails we exit before SSH and auth-key setup. Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> --- data/PVE/API2/ClusterConfig.pm | 10 ++++----- data/PVE/Cluster/Setup.pm | 40 ++++++++++------------------------ data/PVE/Corosync.pm | 29 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 34 deletions(-) diff --git a/data/PVE/API2/ClusterConfig.pm b/data/PVE/API2/ClusterConfig.pm index bff0c48..0454947 100644 --- a/data/PVE/API2/ClusterConfig.pm +++ b/data/PVE/API2/ClusterConfig.pm @@ -115,6 +115,11 @@ __PACKAGE__->register_method ({ my $authuser = $rpcenv->get_user(); my $code = sub { + my $nodename = PVE::INotify::nodename(); + + # get the corosync basis config for the new cluster + my $config = PVE::Corosync::create_conf($nodename, $param); + STDOUT->autoflush(); PVE::Cluster::Setup::setup_sshd_config(1); PVE::Cluster::Setup::setup_rootsshconfig(); @@ -124,11 +129,6 @@ __PACKAGE__->register_method ({ if !-f $authfile; die "no authentication key available\n" if -f !$authfile; - my $nodename = PVE::INotify::nodename(); - - # get the corosync basis config for the new cluster - my $config = PVE::Corosync::create_conf($nodename, $param); - print "Writing corosync config to /etc/pve/corosync.conf\n"; PVE::Corosync::atomic_write_conf($config); diff --git a/data/PVE/Cluster/Setup.pm b/data/PVE/Cluster/Setup.pm index c6f6c9e..77d3664 100644 --- a/data/PVE/Cluster/Setup.pm +++ b/data/PVE/Cluster/Setup.pm @@ -566,55 +566,37 @@ sub assert_joinable { my ($local_addr, $links, $force) = @_; my $errors = ''; - my $error = sub { $errors .= "* $_[0]\n"; }; + my $error = sub { $errors .= "* $_[0]"; }; if (-f $authfile) { - $error->("authentication key '$authfile' already exists"); + $error->("authentication key '$authfile' already exists\n"); } if (-f $clusterconf) { - $error->("cluster config '$clusterconf' already exists"); + $error->("cluster config '$clusterconf' already exists\n"); } my $vmlist = PVE::Cluster::get_vmlist(); if ($vmlist && $vmlist->{ids} && scalar(keys %{$vmlist->{ids}})) { - $error->("this host already contains virtual guests"); + $error->("this host already contains virtual guests\n"); } if (PVE::Tools::run_command(['corosync-quorumtool', '-l'], noerr => 1, quiet => 1) == 0) { - $error->("corosync is already running, is this node already in a cluster?!"); - } - - # check if corosync ring IPs are configured on the current nodes interfaces - my $check_ip = sub { - my $ip = shift // return; - my $logid = shift; - if (!PVE::JSONSchema::pve_verify_ip($ip, 1)) { - my $host = $ip; - eval { $ip = PVE::Network::get_ip_from_hostname($host); }; - if ($@) { - $error->("$logid: 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->("$logid: cannot use IP '$ip', it must be configured exactly once on local node!\n") - if (scalar(@$configured_ips) != 1); - }; + $error->("corosync is currently running, is this node already in a cluster?\n"); + } - $check_ip->($local_addr, 'local node address'); + eval { PVE::Corosync::check_ip_configured($local_addr, 'local node address'); }; + $error->($@) if $@; if ($links) { foreach my $link (keys %$links) { - $check_ip->($links->{$link}->{address}, "link$link"); + eval { PVE::Corosync::check_ip_configured($links->{$link}->{address}, "link$link"); }; + $error->($@) if $@; } } if ($errors) { - warn "detected the following error(s):\n$errors"; + warn "Detected the following error(s):\n$errors"; die "Check if node may join a cluster failed!\n" if !$force; } } diff --git a/data/PVE/Corosync.pm b/data/PVE/Corosync.pm index 69927ff..19c8976 100644 --- a/data/PVE/Corosync.pm +++ b/data/PVE/Corosync.pm @@ -11,6 +11,7 @@ use Socket qw(AF_INET AF_INET6 inet_ntop); use PVE::Cluster; use PVE::JSONSchema; +use PVE::Network; use PVE::Tools; use PVE::Tools qw($IPV4RE $IPV6RE); @@ -267,6 +268,32 @@ sub atomic_write_conf { || die "activating corosync.conf.new failed - $!\n"; } +# check if an IP address is configured exactly once on the local node, so that +# corosync can safely use it as a link +sub check_ip_configured { + my ($ip, $logid) = @_; + + return if !defined($ip); + $logid //= "error"; + + if (!PVE::JSONSchema::pve_verify_ip($ip, 1)) { + my $host = $ip; + eval { $ip = PVE::Network::get_ip_from_hostname($host); }; + if ($@) { + die "$logid: cannot use '$host': $@\n"; + } + } + + my $cidr = (Net::IP::ip_is_ipv6($ip)) ? "$ip/128" : "$ip/32"; + my $configured_ips = PVE::Network::get_local_ip_from_cidr($cidr); + + die "$logid: cannot use IP '$ip', it is not configured on local node (must exist exactly once)!\n" + if (scalar(@$configured_ips) < 1); + + die "$logid: cannot use IP '$ip', it is configured multiple times on local node (must exist exactly once)!\n" + if (scalar(@$configured_ips) > 1); +}; + # for creating a new cluster with the current node # params are those from the API/CLI cluster create call sub create_conf { @@ -317,6 +344,8 @@ sub create_conf { foreach my $lnum (keys %$links) { my $link = $links->{$lnum}; + check_ip_configured($link->{address}, "link$lnum"); + $totem->{interface}->{$lnum} = { linknumber => $lnum }; my $prio = $link->{priority}; -- 2.20.1 _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel