[pve-devel] [PATCH container 1/1] cloud-init: add support for multiple IP addresses

Julian Pawlowski julian at pawlowski.me
Wed Oct 24 08:57:34 CEST 2018


Signed-off-by: Julian Pawlowski <julian at pawlowski.me>
---
 PVE/QemuServer.pm           |  50 ++++-----
 PVE/QemuServer/Cloudinit.pm | 202 +++++++++++++++++++++---------------
 2 files changed, 145 insertions(+), 107 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 933f54f..9bd8c18 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -773,36 +773,38 @@ PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
 
 my $ipconfig_fmt = {
     ip => {
-	type => 'string',
-	format => 'pve-ipv4-config',
-	format_description => 'IPv4Format/CIDR',
-	description => 'IPv4 address in CIDR format.',
-	optional => 1,
-	default => 'dhcp',
+        type               => 'string',
+        format             => 'pve-ipv4-config',
+        format_description => 'IPv4Format/CIDR',
+        description        => 'IPv4 address in CIDR format.',
+        optional           => 1,
+        multiple           => 1,
+        default            => 'dhcp',
     },
     gw => {
-	type => 'string',
-	format => 'ipv4',
-	format_description => 'GatewayIPv4',
-	description => 'Default gateway for IPv4 traffic.',
-	optional => 1,
-	requires => 'ip',
+        type               => 'string',
+        format             => 'ipv4',
+        format_description => 'GatewayIPv4',
+        description        => 'Default gateway for IPv4 traffic.',
+        optional           => 1,
+        requires           => 'ip',
     },
     ip6 => {
-	type => 'string',
-	format => 'pve-ipv6-config',
-	format_description => 'IPv6Format/CIDR',
-	description => 'IPv6 address in CIDR format.',
-	optional => 1,
-	default => 'dhcp',
+        type               => 'string',
+        format             => 'pve-ipv6-config',
+        format_description => 'IPv6Format/CIDR',
+        description        => 'IPv6 address in CIDR format.',
+        optional           => 1,
+        multiple           => 1,
+        default            => 'dhcp',
     },
     gw6 => {
-	type => 'string',
-	format => 'ipv6',
-	format_description => 'GatewayIPv6',
-	description => 'Default gateway for IPv6 traffic.',
-	optional => 1,
-	requires => 'ip6',
+        type               => 'string',
+        format             => 'ipv6',
+        format_description => 'GatewayIPv6',
+        description        => 'Default gateway for IPv6 traffic.',
+        optional           => 1,
+        requires           => 'ip6',
     },
 };
 PVE::JSONSchema::register_format('pve-qm-ipconfig', $ipconfig_fmt);
diff --git a/PVE/QemuServer/Cloudinit.pm b/PVE/QemuServer/Cloudinit.pm
index 53f1de9..a0ddd37 100644
--- a/PVE/QemuServer/Cloudinit.pm
+++ b/PVE/QemuServer/Cloudinit.pm
@@ -162,34 +162,48 @@ sub configdrive2_network {
 
     my @ifaces = grep(/^net(\d+)$/, keys %$conf);
     foreach my $iface (@ifaces) {
-	(my $id = $iface) =~ s/^net//;
-	next if !$conf->{"ipconfig$id"};
-	my $net = PVE::QemuServer::parse_ipconfig($conf->{"ipconfig$id"});
-	$id = "eth$id";
-
-	$content .="auto $id\n";
-	if ($net->{ip}) {
-	    if ($net->{ip} eq 'dhcp') {
-		$content .= "iface $id inet dhcp\n";
-	    } else {
-		my ($addr, $mask) = split_ip4($net->{ip});
-		$content .= "iface $id inet static\n";
-		$content .= "        address $addr\n";
-		$content .= "        netmask $mask\n";
-		$content .= "        gateway $net->{gw}\n" if $net->{gw};
-	    }
-	}
-	if ($net->{ip6}) {
-	    if ($net->{ip6} =~ /^(auto|dhcp)$/) {
-		$content .= "iface $id inet6 $1\n";
-	    } else {
-		my ($addr, $mask) = split('/', $net->{ip6});
-		$content .= "iface $id inet6 static\n";
-		$content .= "        address $addr\n";
-		$content .= "        netmask $mask\n";
-		$content .= "        gateway $net->{gw6}\n" if $net->{gw6};
-	    }
-	}
+        ( my $id = $iface ) =~ s/^net//;
+        next if !$conf->{"ipconfig$id"};
+        my $net = PVE::QemuServer::parse_ipconfig( $conf->{"ipconfig$id"} );
+        $id = "eth$id";
+
+        $content .= "auto $id\n";
+        if ( $net->{ip} ) {
+            my $loop = 0;
+            foreach my $ip ( @{ $net->{ip} } ) {
+                if ( $ip eq 'dhcp' ) {
+                    $content .= "iface $id inet dhcp\n";
+                    last;
+                }
+                else {
+                    my ( $addr, $mask ) = split_ip4($ip);
+                    $content .= "iface $id inet static\n";
+                    $content .= "        address $addr\n";
+                    $content .= "        netmask $mask\n";
+                    $content .= "        gateway $net->{gw}\n"
+                      if ( $net->{gw} && !$loop );
+                }
+                $loop++;
+            }
+        }
+        if ( $net->{ip6} ) {
+            my $loop = 0;
+            foreach my $ip ( @{ $net->{ip6} } ) {
+                if ( $net->{ip6} =~ /^(auto|dhcp)$/ ) {
+                    $content .= "iface $id inet6 $1\n";
+                    last;
+                }
+                else {
+                    my ( $addr, $mask ) = split( '/', $net->{ip6} );
+                    $content .= "iface $id inet6 static\n";
+                    $content .= "        address $addr\n";
+                    $content .= "        netmask $mask\n";
+                    $content .= "        gateway $net->{gw6}\n"
+                      if ( $net->{gw6} && !$loop );
+                }
+                $loop++;
+            }
+        }
     }
 
     return $content;
@@ -254,20 +268,28 @@ sub nocloud_network_v2 {
 	         . "${i}    macaddress: \"$mac\"\n"
 	         . "${i}set-name: eth$id\n";
 	my @addresses;
-	if (defined(my $ip = $ipconfig->{ip})) {
-	    if ($ip eq 'dhcp') {
-		$content .= "${i}dhcp4: true\n";
-	    } else {
-		push @addresses, $ip;
-	    }
-	}
-	if (defined(my $ip = $ipconfig->{ip6})) {
-	    if ($ip eq 'dhcp') {
-		$content .= "${i}dhcp6: true\n";
-	    } else {
-		push @addresses, $ip;
-	    }
-	}
+  if ( $ipconfig->{ip} ) {
+      foreach my $ip ( @{ $ipconfig->{ip} } ) {
+          if ( $ip eq 'dhcp' ) {
+              $content .= "${i}dhcp4: true\n";
+              last;
+          }
+          else {
+              push @addresses, $ip;
+          }
+      }
+  }
+  if ( $ipconfig->{ip6} ) {
+      foreach my $ip ( @{ $ipconfig->{ip6} } ) {
+          if ( $ip eq 'dhcp' ) {
+              $content .= "${i}dhcp6: true\n";
+              last;
+          }
+          else {
+              push @addresses, $ip;
+          }
+      }
+  }
 	if (@addresses) {
 	    $content .= "${i}addresses:\n";
 	    $content .= "${i}- $_\n" foreach @addresses;
@@ -307,47 +329,61 @@ sub nocloud_network {
 
     my @ifaces = grep(/^net(\d+)$/, keys %$conf);
     foreach my $iface (@ifaces) {
-	(my $id = $iface) =~ s/^net//;
-	next if !$conf->{"ipconfig$id"};
-
-	# indentation - network interfaces are inside an 'ethernets' hash
-	my $i = '    ';
-
-	my $net = PVE::QemuServer::parse_net($conf->{$iface});
-	my $ipconfig = PVE::QemuServer::parse_ipconfig($conf->{"ipconfig$id"});
-
-	my $mac = lc($net->{macaddr})
-	    or die "network interface '$iface' has no mac address\n";
-
-	$content .= "${i}- type: physical\n"
-	          . "${i}  name: eth$id\n"
-	          . "${i}  mac_address: $mac\n"
-	          . "${i}  subnets:\n";
-	$i .= '  ';
-	if (defined(my $ip = $ipconfig->{ip})) {
-	    if ($ip eq 'dhcp') {
-		$content .= "${i}- type: dhcp4\n";
-	    } else {
-		my ($addr, $mask) = split_ip4($ip);
-		$content .= "${i}- type: static\n"
-		          . "${i}  address: $addr\n"
-		          . "${i}  netmask: $mask\n";
-		if (defined(my $gw = $ipconfig->{gw})) {
-		    $content .= "${i}  gateway: $gw\n";
-		}
-	    }
-	}
-	if (defined(my $ip = $ipconfig->{ip6})) {
-	    if ($ip eq 'dhcp') {
-		$content .= "${i}- type: dhcp6\n";
-	    } else {
-		$content .= "${i}- type: static\n"
-		       . "${i}  address: $ip\n";
-		if (defined(my $gw = $ipconfig->{gw6})) {
-		    $content .= "${i}  gateway: $gw\n";
-		}
-	    }
-	}
+        ( my $id = $iface ) =~ s/^net//;
+        next if !$conf->{"ipconfig$id"};
+
+        # indentation - network interfaces are inside an 'ethernets' hash
+        my $i = '    ';
+
+        my $net = PVE::QemuServer::parse_net( $conf->{$iface} );
+        my $ipconfig =
+          PVE::QemuServer::parse_ipconfig( $conf->{"ipconfig$id"} );
+
+        my $mac = lc( $net->{macaddr} )
+          or die "network interface '$iface' has no mac address\n";
+
+        $content .=
+            "${i}- type: physical\n"
+          . "${i}  name: eth$id\n"
+          . "${i}  mac_address: $mac\n"
+          . "${i}  subnets:\n";
+        $i .= '  ';
+        if ( $ipconfig->{ip} ) {
+            my $loop = 0;
+            foreach my $ip ( @{ $ipconfig->{ip} } ) {
+                if ( $ip eq 'dhcp' ) {
+                    $content .= "${i}- type: dhcp4\n";
+                    last;
+                }
+                else {
+                    my ( $addr, $mask ) = split_ip4($ip);
+                    $content .=
+                        "${i}- type: static\n"
+                      . "${i}  address: $addr\n"
+                      . "${i}  netmask: $mask\n";
+                    if ( !$loop && defined( my $gw = $ipconfig->{gw} ) ) {
+                        $content .= "${i}  gateway: $gw\n";
+                    }
+                }
+                $loop++;
+            }
+        }
+        if ( $ipconfig->{ip6} ) {
+            my $loop = 0;
+            foreach my $ip ( @{ $ipconfig->{ip6} } ) {
+                if ( $ip eq 'dhcp' ) {
+                    $content .= "${i}- type: dhcp6\n";
+                    last;
+                }
+                else {
+                    $content .= "${i}- type: static\n" . "${i}  address: $ip\n";
+                    if ( !$loop && defined( my $gw = $ipconfig->{gw6} ) ) {
+                        $content .= "${i}  gateway: $gw\n";
+                    }
+                }
+                $loop++;
+            }
+        }
     }
 
     my $i = '    ';
-- 
2.19.1




More information about the pve-devel mailing list