[pve-devel] [PATCH 01/20] implement cloudinit v2
Alexandre Derumier
aderumier at odiso.com
Sun Jun 18 15:03:07 CEST 2017
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
PVE/QemuServer.pm | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
debian/control | 1 +
2 files changed, 153 insertions(+), 3 deletions(-)
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 1a4860e..5ec5df8 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -18,11 +18,12 @@ use Cwd 'abs_path';
use IPC::Open3;
use JSON;
use Fcntl;
+use UUID;
use PVE::SafeSyslog;
use Storable qw(dclone);
use PVE::Exception qw(raise raise_param_exc);
use PVE::Storage;
-use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach);
+use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE $IPV4RE);
use PVE::JSONSchema qw(get_standard_option);
use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
use PVE::INotify;
@@ -504,6 +505,27 @@ EODESCR
description => "Select BIOS implementation.",
default => 'seabios',
},
+ searchdomain => {
+ optional => 1,
+ type => 'string',
+ description => "Sets DNS search domains for a container. Create will automatically use the setting from the host if you neither set searchdomain or nameserver.",
+ },
+ nameserver => {
+ optional => 1,
+ type => 'string',
+ description => "Sets DNS server IP address for a container. Create will automatically use the setting from the host if you neither set searchdomain or nameserver.",
+ },
+ sshkey => {
+ optional => 1,
+ type => 'string',
+ description => "Ssh keys for root",
+ },
+ cloudinit => {
+ optional => 1,
+ type => 'boolean',
+ description => "Enable cloudinit config generation.",
+ default => 0,
+ },
};
# what about other qemu settings ?
@@ -653,6 +675,20 @@ my $net_fmt = {
description => 'Whether this interface should be disconnected (like pulling the plug).',
optional => 1,
},
+ cidr => {
+ type => 'string',
+ format => 'CIDR',
+ format_description => 'IP/CIDR',
+ description => 'IP Address for the interface.',
+ optional => 1,
+ },
+ gateway => {
+ type => 'string',
+ format => 'ip',
+ format_description => 'IP',
+ description => 'Default gateway to use with this interface.',
+ optional => 1,
+ },
};
my $netdesc = {
@@ -1227,6 +1263,8 @@ sub get_iso_path {
return get_cdrom_path();
} elsif ($cdrom eq 'none') {
return '';
+ } elsif ($cdrom eq 'cloudinit') {
+ return "/tmp/cloudinit/$vmid/configdrive.iso";
} elsif ($cdrom =~ m|^/|) {
return $cdrom;
} else {
@@ -1238,7 +1276,7 @@ sub get_iso_path {
sub filename_to_volume_id {
my ($vmid, $file, $media) = @_;
- if (!($file eq 'none' || $file eq 'cdrom' ||
+ if (!($file eq 'none' || $file eq 'cdrom' || $file eq 'cloudinit' ||
$file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
return undef if $file =~ m|/|;
@@ -1824,6 +1862,11 @@ sub parse_net {
my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
$res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
}
+ if (my $cidr = $res->{cidr}) {
+ ($res->{address}, $res->{netmask}) = split('/', $cidr);
+ delete $res->{cidr};
+ }
+
return $res;
}
@@ -4514,12 +4557,14 @@ sub vm_start {
PVE::QemuConfig->check_lock($conf) if !$skiplock;
die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
-
+
if (!$statefile && scalar(keys %{$conf->{pending}})) {
vmconfig_apply_pending($vmid, $conf, $storecfg);
$conf = PVE::QemuConfig->load_config($vmid); # update/reload
}
+ generate_cloudinitconfig($conf, $vmid);
+
my $defaults = load_defaults();
# set environment variable useful inside network script
@@ -6500,4 +6545,108 @@ sub nbd_stop {
vm_mon_cmd($vmid, 'nbd-server-stop');
}
+sub generate_cloudinitconfig {
+ my ($conf, $vmid) = @_;
+
+ return if !$conf->{cloudinit};
+
+ my $path = "/tmp/cloudinit/$vmid";
+
+ mkdir "/tmp/cloudinit";
+ mkdir $path;
+ mkdir "$path/drive";
+ mkdir "$path/drive/openstack";
+ mkdir "$path/drive/openstack/latest";
+ mkdir "$path/drive/openstack/content";
+ generate_cloudinit_userdata($conf, $path);
+ generate_cloudinit_metadata($conf, $path);
+ generate_cloudinit_network($conf, $path);
+
+ my $cmd = [];
+ push @$cmd, 'genisoimage';
+ push @$cmd, '-R';
+ push @$cmd, '-V', 'config-2';
+ push @$cmd, '-o', "$path/configdrive.iso";
+ push @$cmd, "$path/drive";
+
+ run_command($cmd);
+ rmtree("$path/drive");
+ my $drive = PVE::QemuServer::parse_drive('ide3', 'cloudinit,media=cdrom');
+ $conf->{'ide3'} = PVE::QemuServer::print_drive($vmid, $drive);
+ update_config_nolock($vmid, $conf, 1);
+
+}
+
+sub generate_cloudinit_userdata {
+ my ($conf, $path) = @_;
+
+ my $content = "#cloud-config\n";
+ my $hostname = $conf->{searchdomain} ? $conf->{name}.".".$conf->{searchdomain} : $conf->{name};
+ $content .= "fqdn: $hostname\n";
+ $content .= "manage_etc_hosts: true\n";
+
+ if ($conf->{sshkey}) {
+ $content .= "users:\n";
+ $content .= " - default\n";
+ $content .= " - name: root\n";
+ $content .= " ssh-authorized-keys:\n";
+ $content .= " - $conf->{sshkey}\n";
+ }
+
+ $content .= "package_upgrade: true\n";
+
+ my $fn = "$path/drive/openstack/latest/user_data";
+ file_write($fn, $content);
+
+}
+
+sub generate_cloudinit_metadata {
+ my ($conf, $path) = @_;
+
+ my ($uuid, $uuid_str);
+ UUID::generate($uuid);
+ UUID::unparse($uuid, $uuid_str);
+
+ my $content = "{\n";
+ $content .= " \"uuid\": \"$uuid_str\",\n";
+ $content .= " \"network_config\" :{ \"content_path\": \"/content/0000\"}\n";
+ $content .= "}\n";
+
+ my $fn = "$path/drive/openstack/latest/meta_data.json";
+
+ return file_write($fn, $content);
+
+
+}
+
+sub generate_cloudinit_network {
+ my ($conf, $path) = @_;
+
+ my $content = "auto lo\n";
+ $content .="iface lo inet loopback\n\n";
+
+ foreach my $opt (keys %$conf) {
+ next if $opt !~ m/^net(\d+)$/;
+ my $net = parse_net($conf->{$opt});
+ $opt =~ s/net/eth/;
+
+ $content .="auto $opt\n";
+ if ($net->{address}) {
+ $content .="iface $opt inet static\n";
+ $content .=" address $net->{address}\n";
+ $content .=" netmask $PVE::Network::ipv4_reverse_mask->[$net->{netmask}]\n";
+ $content .=" gateway $net->{gateway}\n" if $net->{gateway};
+ } else {
+ $content .="iface $opt inet dhcp\n";
+ }
+ }
+
+ $content .=" dns-nameservers $conf->{nameserver}\n" if $conf->{nameserver};
+ $content .=" dns-search $conf->{searchdomain}\n" if $conf->{searchdomain};
+
+ my $fn = "$path/drive/openstack/content/0000";
+ file_write($fn, $content);
+
+}
+
1;
diff --git a/debian/control b/debian/control
index c2000e7..d0e7d47 100644
--- a/debian/control
+++ b/debian/control
@@ -30,6 +30,7 @@ Depends: libc6 (>= 2.7-18),
dbus,
libpve-common-perl (>= 4.0-92),
libpve-guest-common-perl,
+ genisoimage,
${perl:Depends},
${shlibs:Depends}
Description: Qemu Server Tools
--
2.11.0
More information about the pve-devel
mailing list