* [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
* 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
* [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