public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
* [pve-devel] [PATCH qemu-server 0/4] RFC: cloudinit pending behaviour change
@ 2021-03-19 12:06 Alexandre Derumier
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config Alexandre Derumier
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Alexandre Derumier @ 2021-03-19 12:06 UTC (permalink / raw)
  To: pve-devel

Hi,

This is an attempt to cleanup current behaviour of cloudinit online changes.

Currently, we setup cloudinit options as pending, until we generate the config drive.

This is not 100% true, because some option like vm name, nic mac address can be changed,
without going to pending, so user can't known if it need to regenerated it.

Also, some can are very difficult to handle, if you hotplug a nic but it's failing,so pending,
then you defined an ipconfig, and then you revert hotplug.
or if you delete a nic, the ipconfig is no more displayed in the gui.


So, instead of setting cloudinit values in pending,
this patch serie copy the current cloudinit config in a new section [CLOUDINIT],
when the config drive is generated.
This is only an hint, to allow to display diff between the generated cloudinit
drive, and the current vm config.

A new specific cloudinit config api is added too, merging ipaddrX && netX mac
in same field, and displaying the diff between current and generated config.




Alexandre Derumier (4):
  cloudinit: add cloudinit section for current generated config.
  generate cloudinit when vm is offline too
  cloudinit: make cloudnit options fastplug
  api2: add cloudinit config api

 PVE/API2/Qemu.pm            | 132 ++++++++++++++++++++++++++++++++++++
 PVE/QemuServer.pm           |  60 ++++++++--------
 PVE/QemuServer/Cloudinit.pm |  32 +++++++++
 3 files changed, 193 insertions(+), 31 deletions(-)

-- 
2.20.1




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config.
  2021-03-19 12:06 [pve-devel] [PATCH qemu-server 0/4] RFC: cloudinit pending behaviour change Alexandre Derumier
@ 2021-03-19 12:06 ` Alexandre Derumier
  2021-03-24  5:58   ` Thomas Lamprecht
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 2/4] generate cloudinit when vm is offline too Alexandre Derumier
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 7+ messages in thread
From: Alexandre Derumier @ 2021-03-19 12:06 UTC (permalink / raw)
  To: pve-devel

Instead using vm pending options for pending cloudinit generated config,

write current generated cloudinit config in a new [CLOUDINIT] SECTION.

Currently, some options like vm name, nic mac address can be hotplugged,
so they are not way to know if the cloud-init disk is already updated.
---
 PVE/QemuServer.pm           | 22 +++++++++++++++++-----
 PVE/QemuServer/Cloudinit.pm | 32 ++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+), 5 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 57cfe62..f47ae87 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -2135,6 +2135,7 @@ sub parse_vm_config {
 	digest => Digest::SHA::sha1_hex($raw),
 	snapshots => {},
 	pending => {},
+	cloudinit => {},
     };
 
     $filename =~ m|/qemu-server/(\d+)\.conf$|
@@ -2159,6 +2160,11 @@ sub parse_vm_config {
 	    $descr = undef;
 	    $conf = $res->{$section} = {};
 	    next;
+	} elsif ($line =~ m/^\[CLOUDINIT\]\s*$/i) {
+	    $section = 'cloudinit';
+	    $descr = undef;
+	    $conf = $res->{$section} = {};
+	    next;
 
 	} elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
 	    $section = $1;
@@ -2219,7 +2225,6 @@ sub parse_vm_config {
 	    warn "vm $vmid - unable to parse config: $line\n";
 	}
     }
-
     if (defined($descr)) {
 	$descr =~ s/\s+$//;
 	$conf->{description} = $descr;
@@ -2256,7 +2261,7 @@ sub write_vm_config {
 
 	foreach my $key (keys %$cref) {
 	    next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
-		$key eq 'snapstate' || $key eq 'pending';
+		$key eq 'snapstate' || $key eq 'pending' || $key eq 'cloudinit';
 	    my $value = $cref->{$key};
 	    if ($key eq 'delete') {
 		die "propertry 'delete' is only allowed in [PENDING]\n"
@@ -2280,8 +2285,10 @@ sub write_vm_config {
 
     &$cleanup_config($conf->{pending}, 1);
 
+    &$cleanup_config($conf->{cloudinit}, 1);
+
     foreach my $snapname (keys %{$conf->{snapshots}}) {
-	die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
+	die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) =~ m/^(pending|cloudinit)$/; 
 	&$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
     }
 
@@ -2310,7 +2317,7 @@ sub write_vm_config {
 	}
 
 	foreach my $key (sort keys %$conf) {
-	    next if $key =~ /^(digest|description|pending|snapshots)$/;
+	    next if $key =~ /^(digest|description|pending|cloudinit|snapshots)$/;
 	    $raw .= "$key: $conf->{$key}\n";
 	}
 	return $raw;
@@ -2323,6 +2330,11 @@ sub write_vm_config {
 	$raw .= &$generate_raw_config($conf->{pending}, 1);
     }
 
+    if (scalar(keys %{$conf->{cloudinit}})){
+	$raw .= "\n[CLOUDINIT]\n";
+	$raw .= &$generate_raw_config($conf->{cloudinit}, 1);
+    }
+
     foreach my $snapname (sort keys %{$conf->{snapshots}}) {
 	$raw .= "\n[$snapname]\n";
 	$raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
@@ -4702,9 +4714,9 @@ sub vmconfig_apply_pending {
 	    $conf->{$opt} = delete $conf->{pending}->{$opt};
 	}
     }
-
     # write all changes at once to avoid unnecessary i/o
     PVE::QemuConfig->write_config($vmid, $conf);
+
 }
 
 sub vmconfig_update_net {
diff --git a/PVE/QemuServer/Cloudinit.pm b/PVE/QemuServer/Cloudinit.pm
index c464bf3..f4bf925 100644
--- a/PVE/QemuServer/Cloudinit.pm
+++ b/PVE/QemuServer/Cloudinit.pm
@@ -570,6 +570,38 @@ sub generate_cloudinitconfig {
 
 	$generator->($conf, $vmid, $drive, $volname, $storeid);
     });
+
+    my $cloudinitconf = delete $conf->{cloudinit};
+    $cloudinitconf = {};
+
+    my @cloudinit_opts = keys %{PVE::QemuServer::cloudinit_config_properties()};
+    push @cloudinit_opts, 'name';
+
+    foreach my $opt (@cloudinit_opts) {
+
+	if ($opt =~ m/^ipconfig(\d+)/) {
+	    my $netid = "net$1";
+	    next if !defined($conf->{$netid});
+	    $conf->{cloudinit}->{$netid} = $conf->{$netid};
+	} 
+
+	$conf->{cloudinit}->{$opt} = $conf->{$opt} if $conf->{$opt}; 
+    }
+
+    $conf->{cloudinit}->{name} = "VM$vmid" if !$conf->{cloudinit}->{name};
+
+    foreach my $opt (keys %{$conf}) {
+	if (PVE::QemuServer::is_valid_drivename($opt)) {
+	    my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
+	    if (PVE::QemuServer::drive_is_cloudinit($drive)) {
+		$conf->{cloudinit}->{$opt} = $conf->{$opt};
+
+	    }
+	}
+    }
+
+    PVE::QemuConfig->write_config($vmid, $conf);
+
 }
 
 sub dump_cloudinit_config {
-- 
2.20.1




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH qemu-server 2/4] generate cloudinit when vm is offline too
  2021-03-19 12:06 [pve-devel] [PATCH qemu-server 0/4] RFC: cloudinit pending behaviour change Alexandre Derumier
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config Alexandre Derumier
@ 2021-03-19 12:06 ` Alexandre Derumier
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 3/4] cloudinit: make cloudnit options fastplug Alexandre Derumier
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 4/4] api2: add cloudinit config api Alexandre Derumier
  3 siblings, 0 replies; 7+ messages in thread
From: Alexandre Derumier @ 2021-03-19 12:06 UTC (permalink / raw)
  To: pve-devel

Currently, the regenerate button in ui don't do nothing when vm is offline,
and the config is only regenerated at vm start
---
 PVE/QemuServer.pm | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index f47ae87..e831667 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -4701,6 +4701,8 @@ sub vmconfig_apply_pending {
 
     PVE::QemuConfig->cleanup_pending($conf);
 
+    my $generate_cloudnit = undef;
+
     foreach my $opt (keys %{$conf->{pending}}) { # add/change
 	next if $opt eq 'delete'; # just to be sure
 	eval {
@@ -4708,15 +4710,23 @@ sub vmconfig_apply_pending {
 		vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
 	    }
 	};
+
+	if (is_valid_drivename($opt)) {
+	    my $drive = parse_drive($opt, $conf->{pending}->{$opt});
+	    $generate_cloudnit = 1 if drive_is_cloudinit($drive);
+	}
+
 	if (my $err = $@) {
 	    $add_apply_error->($opt, $err);
 	} else {
 	    $conf->{$opt} = delete $conf->{pending}->{$opt};
 	}
     }
+
     # write all changes at once to avoid unnecessary i/o
     PVE::QemuConfig->write_config($vmid, $conf);
 
+    PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid) if $generate_cloudnit;
 }
 
 sub vmconfig_update_net {
-- 
2.20.1




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH qemu-server 3/4] cloudinit: make cloudnit options fastplug
  2021-03-19 12:06 [pve-devel] [PATCH qemu-server 0/4] RFC: cloudinit pending behaviour change Alexandre Derumier
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config Alexandre Derumier
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 2/4] generate cloudinit when vm is offline too Alexandre Derumier
@ 2021-03-19 12:06 ` Alexandre Derumier
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 4/4] api2: add cloudinit config api Alexandre Derumier
  3 siblings, 0 replies; 7+ messages in thread
From: Alexandre Derumier @ 2021-03-19 12:06 UTC (permalink / raw)
  To: pve-devel

---
 PVE/QemuServer.pm | 30 +++---------------------------
 1 file changed, 3 insertions(+), 27 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index e831667..fe05de8 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -4455,9 +4455,10 @@ sub vmconfig_hotplug_pending {
 	$errors->{$opt} = "hotplug problem - $msg";
     };
 
+    my @cloudinit_opts = keys %$confdesc_cloudinit;
     my $changes = 0;
     foreach my $opt (keys %{$conf->{pending}}) { # add/change
-	if ($fast_plug_option->{$opt}) {
+	if ($fast_plug_option->{$opt} || grep { $_ eq $opt } @cloudinit_opts) {
 	    $conf->{$opt} = $conf->{pending}->{$opt};
 	    delete $conf->{pending}->{$opt};
 	    $changes = 1;
@@ -4530,31 +4531,6 @@ sub vmconfig_hotplug_pending {
 	}
     }
 
-    my ($apply_pending_cloudinit, $apply_pending_cloudinit_done);
-    $apply_pending_cloudinit = sub {
-	return if $apply_pending_cloudinit_done; # once is enough
-	$apply_pending_cloudinit_done = 1; # once is enough
-
-	my ($key, $value) = @_;
-
-	my @cloudinit_opts = keys %$confdesc_cloudinit;
-	foreach my $opt (keys %{$conf->{pending}}) {
-	    next if !grep { $_ eq $opt } @cloudinit_opts;
-	    $conf->{$opt} = delete $conf->{pending}->{$opt};
-	}
-
-	my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
-	foreach my $opt (sort keys %$pending_delete_hash) {
-	    next if !grep { $_ eq $opt } @cloudinit_opts;
-	    PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
-	    delete $conf->{$opt};
-	}
-
-	my $new_conf = { %$conf };
-	$new_conf->{$key} = $value;
-	PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
-    };
-
     foreach my $opt (keys %{$conf->{pending}}) {
 	next if $selection && !$selection->{$opt};
 	my $value = $conf->{pending}->{$opt};
@@ -4601,7 +4577,7 @@ sub vmconfig_hotplug_pending {
 		# some changes can be done without hotplug
 		my $drive = parse_drive($opt, $value);
 		if (drive_is_cloudinit($drive)) {
-		    &$apply_pending_cloudinit($opt, $value);
+		    PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
 		}
 		vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
 				     $vmid, $opt, $value, $arch, $machine_type);
-- 
2.20.1




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [pve-devel] [PATCH qemu-server 4/4] api2: add cloudinit config api
  2021-03-19 12:06 [pve-devel] [PATCH qemu-server 0/4] RFC: cloudinit pending behaviour change Alexandre Derumier
                   ` (2 preceding siblings ...)
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 3/4] cloudinit: make cloudnit options fastplug Alexandre Derumier
@ 2021-03-19 12:06 ` Alexandre Derumier
  3 siblings, 0 replies; 7+ messages in thread
From: Alexandre Derumier @ 2021-03-19 12:06 UTC (permalink / raw)
  To: pve-devel

---
 PVE/API2/Qemu.pm | 132 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index ea74c69..9f3a55e 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -1039,6 +1039,138 @@ __PACKAGE__->register_method({
 	return PVE::GuestHelpers::config_with_pending_array($conf, $pending_delete_hash);
    }});
 
+__PACKAGE__->register_method({
+    name => 'vm_cloudinit',
+    path => '{vmid}/cloudinit',
+    method => 'GET',
+    proxyto => 'node',
+    description => "Get the cloudinit configuration with both current and pending values.",
+    permissions => {
+	check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
+    },
+    parameters => {
+	additionalProperties => 0,
+	properties => {
+	    node => get_standard_option('pve-node'),
+	    vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }),
+	},
+    },
+    returns => {
+	type => "array",
+	items => {
+	    type => "object",
+	    properties => {
+		key => {
+		    description => "Configuration option name.",
+		    type => 'string',
+		},
+		value => {
+		    description => "Current value.",
+		    type => 'string',
+		    optional => 1,
+		},
+		pending => {
+		    description => "Pending value.",
+		    type => 'string',
+		    optional => 1,
+		},
+		delete => {
+		    description => "Indicates a pending delete request if present and not 0. " .
+		                   "The value 2 indicates a force-delete request.",
+		    type => 'integer',
+		    minimum => 0,
+		    maximum => 2,
+		    optional => 1,
+		},
+	    },
+	},
+    },
+    code => sub {
+	my ($param) = @_;
+
+	my $vmid = $param->{vmid};
+	my $conf = PVE::QemuConfig->load_config($vmid);
+
+	if( defined($conf->{cipassword}) && 
+	    defined($conf->{cloudinit}->{cipassword}) && 
+	    $conf->{cipassword} ne $conf->{cloudinit}->{cipassword}) {
+	    $conf->{cipassword} = '********** ';
+	} elsif (defined($conf->{cipassword})) {
+	    $conf->{cipassword} = '**********';
+	}
+
+	$conf->{cloudinit}->{cipassword} = '**********' if defined($conf->{cloudinit}->{cipassword});
+	
+
+	my $cloudinit_current = $conf->{cloudinit};
+	my $res = [];
+
+	my @cloudinit_opts = keys %{PVE::QemuServer::cloudinit_config_properties()};
+	push @cloudinit_opts, 'name';
+
+
+	#add cloud-init drive 
+	my $drives = {};
+	PVE::QemuConfig->foreach_volume($conf, sub {
+                my ($ds, $drive) = @_;
+		$drives->{$ds} = 1 if PVE::QemuServer::drive_is_cloudinit($drive);
+        });
+
+	PVE::QemuConfig->foreach_volume($cloudinit_current, sub {
+                my ($ds, $drive) = @_;
+		$drives->{$ds} = 1 if PVE::QemuServer::drive_is_cloudinit($drive);
+        });
+	foreach my $ds (keys %{$drives}) {
+	    push @cloudinit_opts, $ds;
+	}
+
+
+	$conf->{name} = "VM$vmid" if !$conf->{name};
+	
+	my $print_net_addr = sub {
+	    my ($conf, $opt, $netid) = @_;
+
+	    if (defined($conf->{$netid})) {
+	        
+		my $net = PVE::QemuServer::parse_net($conf->{$netid});
+		if (defined($conf->{$opt})) {
+		    $conf->{$opt} .= ",macaddr=".$net->{macaddr} if $net->{macaddr};
+		} else {
+		    $conf->{$opt} = "";
+		}
+	    }
+	};
+
+	foreach my $opt (@cloudinit_opts) {
+
+	    #add macaddr to ipconfig
+	    if ($opt =~ m/^ipconfig(\d+)/) {
+		my $netid = "net$1";
+		next if !defined($conf->{$netid}) && !defined($cloudinit_current->{$netid}) && !defined($conf->{$opt}) && !defined($cloudinit_current->{$opt} );
+
+		&$print_net_addr($conf, $opt, $netid);
+		&$print_net_addr($cloudinit_current, $opt, $netid);
+	    }
+
+	    my $item = {
+		key => $opt,
+	    };
+	    if ($cloudinit_current->{$opt}) {
+		$item->{value} = $cloudinit_current->{$opt};
+		if ($conf->{$opt}) {
+		    $item->{pending} = $conf->{$opt} if $conf->{$opt} ne $cloudinit_current->{$opt};
+		} else {
+		    $item->{delete} = 1;
+		}
+	    } else {
+		$item->{pending} = $conf->{$opt} if $conf->{$opt}
+	    }
+    
+	    push @$res, $item;
+	}
+	return $res;
+   }});
+
 # POST/PUT {vmid}/config implementation
 #
 # The original API used PUT (idempotent) an we assumed that all operations
-- 
2.20.1




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config.
  2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config Alexandre Derumier
@ 2021-03-24  5:58   ` Thomas Lamprecht
  2021-03-25 16:29     ` aderumier
  0 siblings, 1 reply; 7+ messages in thread
From: Thomas Lamprecht @ 2021-03-24  5:58 UTC (permalink / raw)
  To: Proxmox VE development discussion, Alexandre Derumier

On 19.03.21 13:06, Alexandre Derumier wrote:
> Instead using vm pending options for pending cloudinit generated config,
> 
> write current generated cloudinit config in a new [CLOUDINIT] SECTION.

But that collides with snapshots? E.g., if I make one named CLOUDINIT I get
also a [CLOUDINIT] section in the config?

If we go that way you may want to use a unique identifier, [special:cloudinit]
or the like (colons are not allowed for snapshot names, IIRC).

> 
> Currently, some options like vm name, nic mac address can be hotplugged,
> so they are not way to know if the cloud-init disk is already updated.
> ---
>  PVE/QemuServer.pm           | 22 +++++++++++++++++-----
>  PVE/QemuServer/Cloudinit.pm | 32 ++++++++++++++++++++++++++++++++
>  2 files changed, 49 insertions(+), 5 deletions(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 57cfe62..f47ae87 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -2135,6 +2135,7 @@ sub parse_vm_config {
>  	digest => Digest::SHA::sha1_hex($raw),
>  	snapshots => {},
>  	pending => {},
> +	cloudinit => {},
>      };
>  
>      $filename =~ m|/qemu-server/(\d+)\.conf$|
> @@ -2159,6 +2160,11 @@ sub parse_vm_config {
>  	    $descr = undef;
>  	    $conf = $res->{$section} = {};
>  	    next;
> +	} elsif ($line =~ m/^\[CLOUDINIT\]\s*$/i) {
> +	    $section = 'cloudinit';
> +	    $descr = undef;
> +	    $conf = $res->{$section} = {};
> +	    next;
>  
>  	} elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
>  	    $section = $1;
> @@ -2219,7 +2225,6 @@ sub parse_vm_config {
>  	    warn "vm $vmid - unable to parse config: $line\n";
>  	}
>      }
> -
>      if (defined($descr)) {
>  	$descr =~ s/\s+$//;
>  	$conf->{description} = $descr;
> @@ -2256,7 +2261,7 @@ sub write_vm_config {
>  
>  	foreach my $key (keys %$cref) {
>  	    next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
> -		$key eq 'snapstate' || $key eq 'pending';
> +		$key eq 'snapstate' || $key eq 'pending' || $key eq 'cloudinit';
>  	    my $value = $cref->{$key};
>  	    if ($key eq 'delete') {
>  		die "propertry 'delete' is only allowed in [PENDING]\n"
> @@ -2280,8 +2285,10 @@ sub write_vm_config {
>  
>      &$cleanup_config($conf->{pending}, 1);
>  
> +    &$cleanup_config($conf->{cloudinit}, 1);
> +
>      foreach my $snapname (keys %{$conf->{snapshots}}) {
> -	die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
> +	die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) =~ m/^(pending|cloudinit)$/; 
>  	&$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
>      }
>  
> @@ -2310,7 +2317,7 @@ sub write_vm_config {
>  	}
>  
>  	foreach my $key (sort keys %$conf) {
> -	    next if $key =~ /^(digest|description|pending|snapshots)$/;
> +	    next if $key =~ /^(digest|description|pending|cloudinit|snapshots)$/;
>  	    $raw .= "$key: $conf->{$key}\n";
>  	}
>  	return $raw;
> @@ -2323,6 +2330,11 @@ sub write_vm_config {
>  	$raw .= &$generate_raw_config($conf->{pending}, 1);
>      }
>  
> +    if (scalar(keys %{$conf->{cloudinit}})){
> +	$raw .= "\n[CLOUDINIT]\n";
> +	$raw .= &$generate_raw_config($conf->{cloudinit}, 1);
> +    }
> +
>      foreach my $snapname (sort keys %{$conf->{snapshots}}) {
>  	$raw .= "\n[$snapname]\n";
>  	$raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
> @@ -4702,9 +4714,9 @@ sub vmconfig_apply_pending {
>  	    $conf->{$opt} = delete $conf->{pending}->{$opt};
>  	}
>      }
> -
>      # write all changes at once to avoid unnecessary i/o
>      PVE::QemuConfig->write_config($vmid, $conf);
> +
>  }
>  
>  sub vmconfig_update_net {
> diff --git a/PVE/QemuServer/Cloudinit.pm b/PVE/QemuServer/Cloudinit.pm
> index c464bf3..f4bf925 100644
> --- a/PVE/QemuServer/Cloudinit.pm
> +++ b/PVE/QemuServer/Cloudinit.pm
> @@ -570,6 +570,38 @@ sub generate_cloudinitconfig {
>  
>  	$generator->($conf, $vmid, $drive, $volname, $storeid);
>      });
> +
> +    my $cloudinitconf = delete $conf->{cloudinit};
> +    $cloudinitconf = {};
> +
> +    my @cloudinit_opts = keys %{PVE::QemuServer::cloudinit_config_properties()};
> +    push @cloudinit_opts, 'name';
> +
> +    foreach my $opt (@cloudinit_opts) {
> +
> +	if ($opt =~ m/^ipconfig(\d+)/) {
> +	    my $netid = "net$1";
> +	    next if !defined($conf->{$netid});
> +	    $conf->{cloudinit}->{$netid} = $conf->{$netid};
> +	} 
> +
> +	$conf->{cloudinit}->{$opt} = $conf->{$opt} if $conf->{$opt}; 
> +    }
> +
> +    $conf->{cloudinit}->{name} = "VM$vmid" if !$conf->{cloudinit}->{name};
> +
> +    foreach my $opt (keys %{$conf}) {
> +	if (PVE::QemuServer::is_valid_drivename($opt)) {
> +	    my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
> +	    if (PVE::QemuServer::drive_is_cloudinit($drive)) {
> +		$conf->{cloudinit}->{$opt} = $conf->{$opt};
> +
> +	    }
> +	}
> +    }
> +
> +    PVE::QemuConfig->write_config($vmid, $conf);
> +
>  }
>  
>  sub dump_cloudinit_config {
> 





^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config.
  2021-03-24  5:58   ` Thomas Lamprecht
@ 2021-03-25 16:29     ` aderumier
  0 siblings, 0 replies; 7+ messages in thread
From: aderumier @ 2021-03-25 16:29 UTC (permalink / raw)
  To: Thomas Lamprecht, Proxmox VE development discussion

> But that collides with snapshots? E.g., if I make one named CLOUDINIT
> I get
> also a [CLOUDINIT] section in the config?
> 
oh, you are right indeed. I have added a check for new snasphots, but
user could
have already a snapshot called CLOUDINIT. 

> If we go that way you may want to use a unique identifier,
> [special:cloudinit]
> or the like (colons are not allowed for snapshot names, IIRC).

ok, I'll rework my patch .

Thanks for the review !

Le mercredi 24 mars 2021 à 06:58 +0100, Thomas Lamprecht a écrit :
> On 19.03.21 13:06, Alexandre Derumier wrote:
> > Instead using vm pending options for pending cloudinit generated
> > config,
> > 
> > write current generated cloudinit config in a new [CLOUDINIT]
> > SECTION.
> 
> But that collides with snapshots? E.g., if I make one named CLOUDINIT
> I get
> also a [CLOUDINIT] section in the config?
> 
> If we go that way you may want to use a unique identifier,
> [special:cloudinit]
> or the like (colons are not allowed for snapshot names, IIRC).
> 
> > 
> > Currently, some options like vm name, nic mac address can be
> > hotplugged,
> > so they are not way to know if the cloud-init disk is already
> > updated.
> > ---
> >  PVE/QemuServer.pm           | 22 +++++++++++++++++-----
> >  PVE/QemuServer/Cloudinit.pm | 32 ++++++++++++++++++++++++++++++++
> >  2 files changed, 49 insertions(+), 5 deletions(-)
> > 
> > diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> > index 57cfe62..f47ae87 100644
> > --- a/PVE/QemuServer.pm
> > +++ b/PVE/QemuServer.pm
> > @@ -2135,6 +2135,7 @@ sub parse_vm_config {
> >         digest => Digest::SHA::sha1_hex($raw),
> >         snapshots => {},
> >         pending => {},
> > +       cloudinit => {},
> >      };
> >  
> >      $filename =~ m|/qemu-server/(\d+)\.conf$|
> > @@ -2159,6 +2160,11 @@ sub parse_vm_config {
> >             $descr = undef;
> >             $conf = $res->{$section} = {};
> >             next;
> > +       } elsif ($line =~ m/^\[CLOUDINIT\]\s*$/i) {
> > +           $section = 'cloudinit';
> > +           $descr = undef;
> > +           $conf = $res->{$section} = {};
> > +           next;
> >  
> >         } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
> >             $section = $1;
> > @@ -2219,7 +2225,6 @@ sub parse_vm_config {
> >             warn "vm $vmid - unable to parse config: $line\n";
> >         }
> >      }
> > -
> >      if (defined($descr)) {
> >         $descr =~ s/\s+$//;
> >         $conf->{description} = $descr;
> > @@ -2256,7 +2261,7 @@ sub write_vm_config {
> >  
> >         foreach my $key (keys %$cref) {
> >             next if $key eq 'digest' || $key eq 'description' ||
> > $key eq 'snapshots' ||
> > -               $key eq 'snapstate' || $key eq 'pending';
> > +               $key eq 'snapstate' || $key eq 'pending' || $key eq
> > 'cloudinit';
> >             my $value = $cref->{$key};
> >             if ($key eq 'delete') {
> >                 die "propertry 'delete' is only allowed in
> > [PENDING]\n"
> > @@ -2280,8 +2285,10 @@ sub write_vm_config {
> >  
> >      &$cleanup_config($conf->{pending}, 1);
> >  
> > +    &$cleanup_config($conf->{cloudinit}, 1);
> > +
> >      foreach my $snapname (keys %{$conf->{snapshots}}) {
> > -       die "internal error: snapshot name '$snapname' is
> > forbidden" if lc($snapname) eq 'pending';
> > +       die "internal error: snapshot name '$snapname' is
> > forbidden" if lc($snapname) =~ m/^(pending|cloudinit)$/; 
> >         &$cleanup_config($conf->{snapshots}->{$snapname}, undef,
> > $snapname);
> >      }
> >  
> > @@ -2310,7 +2317,7 @@ sub write_vm_config {
> >         }
> >  
> >         foreach my $key (sort keys %$conf) {
> > -           next if $key =~
> > /^(digest|description|pending|snapshots)$/;
> > +           next if $key =~
> > /^(digest|description|pending|cloudinit|snapshots)$/;
> >             $raw .= "$key: $conf->{$key}\n";
> >         }
> >         return $raw;
> > @@ -2323,6 +2330,11 @@ sub write_vm_config {
> >         $raw .= &$generate_raw_config($conf->{pending}, 1);
> >      }
> >  
> > +    if (scalar(keys %{$conf->{cloudinit}})){
> > +       $raw .= "\n[CLOUDINIT]\n";
> > +       $raw .= &$generate_raw_config($conf->{cloudinit}, 1);
> > +    }
> > +
> >      foreach my $snapname (sort keys %{$conf->{snapshots}}) {
> >         $raw .= "\n[$snapname]\n";
> >         $raw .= &$generate_raw_config($conf->{snapshots}-
> > >{$snapname});
> > @@ -4702,9 +4714,9 @@ sub vmconfig_apply_pending {
> >             $conf->{$opt} = delete $conf->{pending}->{$opt};
> >         }
> >      }
> > -
> >      # write all changes at once to avoid unnecessary i/o
> >      PVE::QemuConfig->write_config($vmid, $conf);
> > +
> >  }
> >  
> >  sub vmconfig_update_net {
> > diff --git a/PVE/QemuServer/Cloudinit.pm
> > b/PVE/QemuServer/Cloudinit.pm
> > index c464bf3..f4bf925 100644
> > --- a/PVE/QemuServer/Cloudinit.pm
> > +++ b/PVE/QemuServer/Cloudinit.pm
> > @@ -570,6 +570,38 @@ sub generate_cloudinitconfig {
> >  
> >         $generator->($conf, $vmid, $drive, $volname, $storeid);
> >      });
> > +
> > +    my $cloudinitconf = delete $conf->{cloudinit};
> > +    $cloudinitconf = {};
> > +
> > +    my @cloudinit_opts = keys
> > %{PVE::QemuServer::cloudinit_config_properties()};
> > +    push @cloudinit_opts, 'name';
> > +
> > +    foreach my $opt (@cloudinit_opts) {
> > +
> > +       if ($opt =~ m/^ipconfig(\d+)/) {
> > +           my $netid = "net$1";
> > +           next if !defined($conf->{$netid});
> > +           $conf->{cloudinit}->{$netid} = $conf->{$netid};
> > +       } 
> > +
> > +       $conf->{cloudinit}->{$opt} = $conf->{$opt} if $conf-
> > >{$opt}; 
> > +    }
> > +
> > +    $conf->{cloudinit}->{name} = "VM$vmid" if !$conf->{cloudinit}-
> > >{name};
> > +
> > +    foreach my $opt (keys %{$conf}) {
> > +       if (PVE::QemuServer::is_valid_drivename($opt)) {
> > +           my $drive = PVE::QemuServer::parse_drive($opt, $conf-
> > >{$opt});
> > +           if (PVE::QemuServer::drive_is_cloudinit($drive)) {
> > +               $conf->{cloudinit}->{$opt} = $conf->{$opt};
> > +
> > +           }
> > +       }
> > +    }
> > +
> > +    PVE::QemuConfig->write_config($vmid, $conf);
> > +
> >  }
> >  
> >  sub dump_cloudinit_config {
> > 
> 
> 



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-03-25 16:29 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-19 12:06 [pve-devel] [PATCH qemu-server 0/4] RFC: cloudinit pending behaviour change Alexandre Derumier
2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 1/4] cloudinit: add cloudinit section for current generated config Alexandre Derumier
2021-03-24  5:58   ` Thomas Lamprecht
2021-03-25 16:29     ` aderumier
2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 2/4] generate cloudinit when vm is offline too Alexandre Derumier
2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 3/4] cloudinit: make cloudnit options fastplug Alexandre Derumier
2021-03-19 12:06 ` [pve-devel] [PATCH qemu-server 4/4] api2: add cloudinit config api Alexandre Derumier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal