ceph: create mon: fix & improve check if IP is in public net

If a CIDR gets passed to Net::IP it is expected to not be from the
middle of  an subnet, i.e., 192.168.1.12/24 is *not* OK but
192.168.1.0/24 would be OK.

As the Network/interfaces files also accepts CIDR notation for the
'address' param (now also for IPv4) this let to problems in our node
monitor IP detection code, which used the interface file and Net::IP to
find any address from the ceph public network.

So change to our newer helper PVE::Network::get_local_ip_from_cidr to
get all configured and ready (=up) IPs from this network.

Also handle the case where multiple networks where returned, add a
parameter to allow specifying one of those and ask the user to do so.

If no public network is configured and no mon-address parameter was
passed, we fall back to the remote node IP of the node, as was done
previously. We expect that the user only overwrites the mon-address
if he knows what he do and omit checks here.
This commit is contained in:
Thomas Lamprecht 2017-11-28 16:32:44 +01:00 committed by Wolfgang Bumiller
parent 0628b7355c
commit 9aad4e2e79

View File

@ -918,24 +918,32 @@ __PACKAGE__->register_method ({
return undef; return undef;
}}); }});
my $find_node_ip = sub { my $find_mon_ip = sub {
my ($cidr) = @_; my ($pubnet, $node, $overwrite_ip) = @_;
my $net = Net::IP->new($cidr) || die Net::IP::Error() . "\n"; if (!$pubnet) {
my $id = $net->version == 6 ? 'address6' : 'address'; return $overwrite_ip // PVE::Cluster::remote_node_ip($node);
my $config = PVE::INotify::read_file('interfaces');
my $ifaces = $config->{ifaces};
foreach my $iface (keys %$ifaces) {
my $d = $ifaces->{$iface};
next if !$d->{$id};
my $a = Net::IP->new($d->{$id});
next if !$a;
return $d->{$id} if $net->overlaps($a);
} }
die "unable to find local address within network '$cidr'\n"; my $allowed_ips = PVE::Network::get_local_ip_from_cidr($pubnet);
die "No IP configured and up from ceph public network '$pubnet'\n"
if scalar(@$allowed_ips) < 1;
if (!$overwrite_ip) {
if (scalar(@$allowed_ips) == 1) {
return $allowed_ips->[0];
}
die "Multiple IPs for ceph public network '$pubnet' detected on $node:\n".
join("\n", @$allowed_ips) ."\nuse 'mon-address' to specify one of them.\n";
} else {
if (grep { $_ eq $overwrite_ip } @$allowed_ips) {
return $overwrite_ip;
}
die "Monitor IP '$overwrite_ip' not in ceph public network '$pubnet'\n"
if !PVE::Network::is_ip_in_cidr($overwrite_ip, $pubnet);
die "Specified monitor IP '$overwrite_ip' not configured or up on $node!\n";
}
}; };
my $create_mgr = sub { my $create_mgr = sub {
@ -1016,6 +1024,12 @@ __PACKAGE__->register_method ({
default => 0, default => 0,
description => "When set, only a monitor will be created.", description => "When set, only a monitor will be created.",
}, },
'mon-address' => {
description => 'Overwrites autodetected monitor IP address. ' .
'Must be in the public network of ceph.',
type => 'string', format => 'ip',
optional => 1,
},
}, },
}, },
returns => { type => 'string' }, returns => { type => 'string' },
@ -1057,12 +1071,8 @@ __PACKAGE__->register_method ({
my $monid = $param->{id} // $param->{node}; my $monid = $param->{id} // $param->{node};
my $monsection = "mon.$monid"; my $monsection = "mon.$monid";
my $ip; my $pubnet = $cfg->{global}->{'public network'};
if (my $pubnet = $cfg->{global}->{'public network'}) { my $ip = $find_mon_ip->($pubnet, $param->{node}, $param->{'mon-address'});
$ip = &$find_node_ip($pubnet);
} else {
$ip = PVE::Cluster::remote_node_ip($param->{node});
}
my $monaddr = Net::IP::ip_is_ipv6($ip) ? "[$ip]:6789" : "$ip:6789"; my $monaddr = Net::IP::ip_is_ipv6($ip) ? "[$ip]:6789" : "$ip:6789";
my $monname = $param->{node}; my $monname = $param->{node};