mirror of
https://git.proxmox.com/git/qemu-server
synced 2025-06-15 13:12:15 +00:00
api2: add cloudinit config api
Signed-off-by: Alexandre Derumier <aderumier@odiso.com> Reviewed-by: Fiona Ebner <f.ebner@proxmox.com>
This commit is contained in:
parent
71d9006b7c
commit
2be1fb0af4
@ -21,6 +21,7 @@ use PVE::ReplicationConfig;
|
|||||||
use PVE::GuestHelpers;
|
use PVE::GuestHelpers;
|
||||||
use PVE::QemuConfig;
|
use PVE::QemuConfig;
|
||||||
use PVE::QemuServer;
|
use PVE::QemuServer;
|
||||||
|
use PVE::QemuServer::Cloudinit;
|
||||||
use PVE::QemuServer::CPUConfig;
|
use PVE::QemuServer::CPUConfig;
|
||||||
use PVE::QemuServer::Drive;
|
use PVE::QemuServer::Drive;
|
||||||
use PVE::QemuServer::ImportDisk;
|
use PVE::QemuServer::ImportDisk;
|
||||||
@ -1311,6 +1312,73 @@ __PACKAGE__->register_method({
|
|||||||
return PVE::GuestHelpers::config_with_pending_array($conf, $pending_delete_hash);
|
return PVE::GuestHelpers::config_with_pending_array($conf, $pending_delete_hash);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
|
__PACKAGE__->register_method({
|
||||||
|
name => 'cloudinit_pending',
|
||||||
|
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 $res = PVE::QemuServer::Cloudinit::get_pending_config($conf, $vmid);
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}});
|
||||||
|
|
||||||
# POST/PUT {vmid}/config implementation
|
# POST/PUT {vmid}/config implementation
|
||||||
#
|
#
|
||||||
# The original API used PUT (idempotent) an we assumed that all operations
|
# The original API used PUT (idempotent) an we assumed that all operations
|
||||||
|
@ -984,6 +984,7 @@ our $cmddef = {
|
|||||||
|
|
||||||
cloudinit => {
|
cloudinit => {
|
||||||
dump => [ "PVE::API2::Qemu", 'cloudinit_generated_config_dump', ['vmid', 'type'], { %node }, sub { print "$_[0]\n"; }],
|
dump => [ "PVE::API2::Qemu", 'cloudinit_generated_config_dump', ['vmid', 'type'], { %node }, sub { print "$_[0]\n"; }],
|
||||||
|
pending => [ "PVE::API2::Qemu", 'cloudinit_pending', ['vmid'], { %node }, \&PVE::GuestHelpers::format_pending ]
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -7,6 +7,7 @@ use File::Path;
|
|||||||
use Digest::SHA;
|
use Digest::SHA;
|
||||||
use URI::Escape;
|
use URI::Escape;
|
||||||
use MIME::Base64 qw(encode_base64);
|
use MIME::Base64 qw(encode_base64);
|
||||||
|
use Storable qw(dclone);
|
||||||
|
|
||||||
use PVE::Tools qw(run_command file_set_contents);
|
use PVE::Tools qw(run_command file_set_contents);
|
||||||
use PVE::Storage;
|
use PVE::Storage;
|
||||||
@ -632,4 +633,82 @@ sub dump_cloudinit_config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_pending_config {
|
||||||
|
my ($conf, $vmid) = @_;
|
||||||
|
|
||||||
|
my $newconf = dclone($conf);
|
||||||
|
|
||||||
|
my $cloudinit_current = $newconf->{cloudinit};
|
||||||
|
my @cloudinit_opts = keys %{PVE::QemuServer::cloudinit_config_properties()};
|
||||||
|
push @cloudinit_opts, 'name';
|
||||||
|
|
||||||
|
#add cloud-init drive
|
||||||
|
my $drives = {};
|
||||||
|
PVE::QemuConfig->foreach_volume($newconf, 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);
|
||||||
|
});
|
||||||
|
for my $ds (keys %{$drives}) {
|
||||||
|
push @cloudinit_opts, $ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newconf->{name} = "VM$vmid" if !$newconf->{name};
|
||||||
|
$cloudinit_current->{name} = "VM$vmid" if !$cloudinit_current->{name};
|
||||||
|
|
||||||
|
#only mac-address is used in cloud-init config.
|
||||||
|
#We don't want to display other pending net changes.
|
||||||
|
my $print_cloudinit_net = sub {
|
||||||
|
my ($conf, $opt) = @_;
|
||||||
|
|
||||||
|
if (defined($conf->{$opt})) {
|
||||||
|
my $net = PVE::QemuServer::parse_net($conf->{$opt});
|
||||||
|
$conf->{$opt} = "macaddr=".$net->{macaddr} if $net->{macaddr};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
my $cloudinit_options = {};
|
||||||
|
for my $opt (@cloudinit_opts) {
|
||||||
|
if ($opt =~ m/^ipconfig(\d+)/) {
|
||||||
|
my $netid = "net$1";
|
||||||
|
|
||||||
|
next if !defined($newconf->{$netid}) && !defined($cloudinit_current->{$netid}) &&
|
||||||
|
!defined($newconf->{$opt}) && !defined($cloudinit_current->{$opt});
|
||||||
|
|
||||||
|
&$print_cloudinit_net($newconf, $netid);
|
||||||
|
&$print_cloudinit_net($cloudinit_current, $netid);
|
||||||
|
$cloudinit_options->{$netid} = 1;
|
||||||
|
}
|
||||||
|
$cloudinit_options->{$opt} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $res = [];
|
||||||
|
|
||||||
|
for my $opt (keys %{$cloudinit_options}) {
|
||||||
|
|
||||||
|
my $item = {
|
||||||
|
key => $opt,
|
||||||
|
};
|
||||||
|
if ($cloudinit_current->{$opt}) {
|
||||||
|
$item->{value} = $cloudinit_current->{$opt};
|
||||||
|
if (defined($newconf->{$opt})) {
|
||||||
|
$item->{pending} = $newconf->{$opt}
|
||||||
|
if $newconf->{$opt} ne $cloudinit_current->{$opt};
|
||||||
|
} else {
|
||||||
|
$item->{delete} = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$item->{pending} = $newconf->{$opt} if $newconf->{$opt}
|
||||||
|
}
|
||||||
|
|
||||||
|
push @$res, $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
Loading…
Reference in New Issue
Block a user