+ eval { PVE::QemuConfig->create_and_lock_config($vmid) };
+ die "Reserving empty config for OVF import to VM $vmid failed: $@" if $@;
+
+ my $conf = PVE::QemuConfig->load_config($vmid);
+ die "Internal error: Expected 'create' lock in config of VM $vmid!"
+ if !PVE::QemuConfig->has_lock($conf, "create");
+
+ $conf->{name} = $parsed->{qm}->{name} if defined($parsed->{qm}->{name});
+ $conf->{memory} = $parsed->{qm}->{memory} if defined($parsed->{qm}->{memory});
+ $conf->{cores} = $parsed->{qm}->{cores} if defined($parsed->{qm}->{cores});
+
+ my $imported_disks = [];
+ eval {
+ # order matters, as do_import() will load_config() internally
+ $conf->{vmgenid} = PVE::QemuServer::generate_uuid();
+ $conf->{smbios1} = PVE::QemuServer::generate_smbios1_uuid();
+ PVE::QemuConfig->write_config($vmid, $conf);
+
+ foreach my $disk (@{ $parsed->{disks} }) {
+ my ($file, $drive) = ($disk->{backing_file}, $disk->{disk_address});
+ my ($name, $volid) = PVE::QemuServer::ImportDisk::do_import($file, $vmid, $storeid, {
+ drive_name => $drive,
+ format => $format,
+ skiplock => 1,
+ });
+ # for cleanup on (later) error
+ push @$imported_disks, $volid;
+ }
+
+ # reload after disks entries have been created
+ $conf = PVE::QemuConfig->load_config($vmid);
+ my $devs = PVE::QemuServer::get_default_bootdevices($conf);
+ $conf->{boot} = PVE::QemuServer::print_bootorder($devs);
+ PVE::QemuConfig->write_config($vmid, $conf);
+ };
+
+ if (my $err = $@) {
+ my $skiplock = 1;
+ warn "error during import, cleaning up created resources...\n";
+ for my $volid (@$imported_disks) {
+ eval { PVE::Storage::vdisk_free($storecfg, $volid) };
+ warn "cleanup of $volid failed: $@\n" if $@;
+ }
+ eval { PVE::QemuServer::destroy_vm($storecfg, $vmid, $skiplock) };
+ warn "Could not destroy VM $vmid: $@" if "$@";
+ die "import failed - $err";
+ }
+
+ PVE::QemuConfig->remove_lock($vmid, "create");
+
+ return;
+
+ }
+});
+
+__PACKAGE__->register_method({
+ name => 'exec',
+ path => 'exec',
+ method => 'POST',
+ protected => 1,
+ description => "Executes the given command via the guest agent",
+ parameters => {
+ additionalProperties => 0,
+ properties => {
+ node => get_standard_option('pve-node'),
+ vmid => get_standard_option('pve-vmid', {
+ completion => \&PVE::QemuServer::complete_vmid_running }),
+ synchronous => {
+ type => 'boolean',
+ optional => 1,
+ default => 1,
+ description => "If set to off, returns the pid immediately instead of waiting for the commmand to finish or the timeout.",
+ },
+ 'timeout' => {
+ type => 'integer',
+ description => "The maximum time to wait synchronously for the command to finish. If reached, the pid gets returned. Set to 0 to deactivate",
+ minimum => 0,
+ optional => 1,
+ default => 30,
+ },
+ 'pass-stdin' => {
+ type => 'boolean',
+ description => "When set, read STDIN until EOF and forward to guest agent via 'input-data' (usually treated as STDIN to process launched by guest agent). Allows maximal 1 MiB.",
+ optional => 1,
+ default => 0,
+ },
+ 'extra-args' => get_standard_option('extra-args'),
+ },
+ },
+ returns => {
+ type => 'object',
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $vmid = $param->{vmid};
+ my $sync = $param->{synchronous} // 1;
+ my $pass_stdin = $param->{'pass-stdin'};
+ if (defined($param->{timeout}) && !$sync) {
+ raise_param_exc({ synchronous => "needs to be set for 'timeout'"});
+ }
+
+ my $input_data = undef;
+ if ($pass_stdin) {
+ $input_data = '';
+ while (my $line = <STDIN>) {
+ $input_data .= $line;
+ if (length($input_data) > 1024*1024) {
+ # not sure how QEMU handles large amounts of data being
+ # passed into the QMP socket, so limit to be safe
+ die "'input-data' (STDIN) is limited to 1 MiB, aborting\n";
+ }
+ }
+ }
+
+ my $args = $param->{'extra-args'};
+ $args = undef if !$args || !@$args;
+
+ my $res = PVE::QemuServer::Agent::qemu_exec($vmid, $input_data, $args);