[pve-devel] [PATCH v4 pve-manager] API2 : Network : add network config reload
Alexandre Derumier
aderumier at odiso.com
Tue Oct 2 09:19:38 CEST 2018
This add a new api to online reload networking configuration
with ifupdown2.
This work with native ifupdown2 modules, as ifupdown2 have
interface dependency relationships.
Some specific interfaces options can't be reloaded online
(because kernel don't implement it), it this case, we ifdown/ifup
theses interfaces. (mainly vxlan interfaces options)
---
changelog v4:
- parse running and new config to detect bridge removal && ovs change
instead using diff
- clean whitespaces errors
changelog v3:
- catch errors on reloading, and try to ifdown/ifup interfaces
- if an interfaces really can't be reloaded, of ifdown/ifup,
revert current config of theses interfaces and keep interfaces.new file
changelog v2:
- remove restart option
- check if vm|ct are running on a bridge delete
- run the networking service reload in a task
PVE/API2/Network.pm | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 151 insertions(+), 1 deletion(-)
diff --git a/PVE/API2/Network.pm b/PVE/API2/Network.pm
index 92256863..69a6b158 100644
--- a/PVE/API2/Network.pm
+++ b/PVE/API2/Network.pm
@@ -4,7 +4,7 @@ use strict;
use warnings;
use Net::IP qw(:PROC);
-use PVE::Tools qw(extract_param);
+use PVE::Tools qw(extract_param dir_glob_regex);
use PVE::SafeSyslog;
use PVE::INotify;
use PVE::Exception qw(raise_param_exc);
@@ -471,6 +471,156 @@ __PACKAGE__->register_method({
}});
__PACKAGE__->register_method({
+ name => 'reload_network_config',
+ path => '',
+ method => 'PUT',
+ permissions => {
+ check => ['perm', '/nodes/{node}', [ 'Sys.Modify' ]],
+ },
+ description => "Reload network configuration",
+ protected => 1,
+ proxyto => 'node',
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ },
+ },
+ returns => { type => 'string' },
+ code => sub {
+
+ my ($param) = @_;
+
+ my $rpcenv = PVE::RPCEnvironment::get();
+
+ my $authuser = $rpcenv->get_user();
+
+ my $current_config_file = "/etc/network/interfaces";
+ my $new_config_file = "/etc/network/interfaces.new";
+
+ raise_param_exc({ config => "you need ifupdown2 to reload networking" }) if !-e '/usr/share/ifupdown2';
+ raise_param_exc({ config => "no new network config to apply" }) if !-e $new_config_file;
+
+ #clean-me
+ my $fh = IO::File->new("<$current_config_file");
+ my $running_config = PVE::INotify::read_etc_network_interfaces(1,$fh);
+ $fh->close();
+
+ #clean-me
+ $fh = IO::File->new("<$new_config_file");
+ my $new_config = PVE::INotify::read_etc_network_interfaces(1,$fh);
+ $fh->close();
+
+ my $ovs_changes = undef;
+ my $bridges_delete = {};
+ my $running_ifaces = $running_config->{ifaces};
+ my $new_ifaces = $new_config->{ifaces};
+
+ foreach my $iface (keys %$running_ifaces) {
+ my $running_iface = $running_ifaces->{$iface};
+ my $type = $running_iface->{type};
+ my $new_iface = $new_ifaces->{$iface};
+ my $new_type = $new_iface->{type};
+
+ $bridges_delete->{$iface} = 1 if !defined($new_iface) && $type eq 'bridge';
+ if ($type =~ m/^OVS/) {
+ #deleted ovs
+ $ovs_changes = 1 if !defined($new_iface);
+ #change ovs type to new type
+ $ovs_changes = 1 if $new_type ne $type;
+ #deleted or changed option
+ foreach my $iface_option (keys %$running_iface) {
+ if (!defined($new_iface->{$iface_option}) || ($running_iface->{$iface_option} ne $new_iface->{$iface_option})) {
+ $ovs_changes = 1;
+ }
+ }
+ } else {
+ #change type to ovs
+ $ovs_changes = 1 if $new_type =~ m/^OVS/;
+ }
+ }
+
+ foreach my $iface (keys %$new_ifaces) {
+ my $new_iface = $new_ifaces->{$iface};
+ my $new_type = $new_iface->{type};
+ my $running_iface = $running_ifaces->{$iface};
+ my $type = $running_iface->{type};
+
+ if ($new_type =~ m/^OVS/) {
+ #new ovs
+ $ovs_changes = 1 if !defined($running_iface);
+ #new option
+ foreach my $iface_option (keys %$new_iface) {
+ if (!defined($running_iface->{$iface_option})) {
+ $ovs_changes = 1;
+ }
+ }
+ }
+ }
+
+ raise_param_exc({ config => "reloading config with ovs changes is not possible currently\n" })
+ if $ovs_changes;
+
+ foreach my $bridge (keys %$bridges_delete) {
+
+ my (undef, $interface) = dir_glob_regex("/sys/class/net/$bridge/brif", '(tap|veth|fwpr).*');
+ raise_param_exc({ config => "bridge deletion is not possible currently if vm or ct are running on this bridge\n" })
+ if defined($interface);
+ }
+
+ my $worker = sub {
+
+ PVE::Tools::file_copy($new_config_file, $current_config_file);
+ my $new_config = PVE::INotify::read_file('interfaces');
+
+ my $cmd = ['ifreload', '-a'];
+ my $ifaces_errors = {};
+ my $ifaces_errors_final = {};
+
+ my $err = sub {
+ my $line = shift;
+ if ($line =~ /(warning|error): (\S+):/) {
+ $ifaces_errors->{$2} = 1;
+ print "$2 : error reloading configuration online : try to ifdown/ifdown later : $line \n";
+ }
+ };
+
+ PVE::Tools::run_command($cmd,errfunc => $err);
+
+ my $err2 = sub {
+ my $line = shift;
+ if ($line =~ /(warning|error): (\S+):/) {
+ $ifaces_errors_final->{$2} = 1;
+ print "$2 : error restart: $line \n";
+ }
+ };
+
+ #try ifdown/up for non online change options
+ foreach my $iface (keys %$ifaces_errors) {
+ eval { PVE::Tools::run_command(['ifdown',$iface]) };
+ PVE::Tools::run_command(['ifup',$iface],errfunc => $err2);
+ }
+
+ #if we still have error, recopy old config of failed interfaces in running config
+ #and keep new interface config to try to apply it later
+ if(keys %$ifaces_errors_final > 0 ) {
+ foreach my $iface (keys %$ifaces_errors_final) {
+ print "error: $iface config has not been applied\n";
+ delete $new_config->{ifaces}->{$iface};
+ $new_config->{ifaces}->{$iface} = $running_config->{ifaces}->{$iface};
+ }
+ #clean-me
+ my $fh = IO::File->new(">$current_config_file");
+ PVE::INotify::write_etc_network_interfaces(1, $fh, $new_config);
+ $fh->close();
+ } else {
+ unlink $new_config_file;
+ }
+ };
+ return $rpcenv->fork_worker('srvreload', 'networking', $authuser, $worker);
+ }});
+
+__PACKAGE__->register_method({
name => 'delete_network',
path => '{iface}',
method => 'DELETE',
--
2.11.0
More information about the pve-devel
mailing list