}
};
+my $cicustom_fmt = {
+ meta => {
+ type => 'string',
+ optional => 1,
+ description => 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
+ format => 'pve-volume-id',
+ format_description => 'volume',
+ },
+ network => {
+ type => 'string',
+ optional => 1,
+ description => 'Specify a custom file containing all network data passed to the VM via cloud-init.',
+ format => 'pve-volume-id',
+ format_description => 'volume',
+ },
+ user => {
+ type => 'string',
+ optional => 1,
+ description => 'Specify a custom file containing all user data passed to the VM via cloud-init.',
+ format => 'pve-volume-id',
+ format_description => 'volume',
+ },
+};
+PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
+
my $confdesc_cloudinit = {
citype => {
optional => 1,
type => 'string',
description => 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
},
+ cicustom => {
+ optional => 1,
+ type => 'string',
+ description => 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
+ format => 'pve-qm-cicustom',
+ },
searchdomain => {
optional => 1,
type => 'string',
next if !$d;
my $pcie = $d->{pcie};
- if($pcie){
+ if ($pcie) {
die "q35 machine model is not enabled" if !$q35;
# win7 wants to have the pcie devices directly on the pcie bus
# instead of in the root port
} else {
$pciaddr = print_pcie_addr("hostpci$i");
}
- }else{
+ } else {
$pciaddr = print_pci_addr("hostpci$i", $bridges, $arch, $machine_type);
}
if ($conf->{ivshmem}) {
my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
+
my $bus;
if ($q35) {
$bus = print_pcie_addr("ivshmem");
} else {
$bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
}
- my $path = '/dev/shm/pve-shm-';
- if ($ivshmem->{name}) {
- $path .= $ivshmem->{name};
- } else {
- $path .= $vmid;
- }
+
+ my $ivshmem_name = $ivshmem->{name} // $vmid;
+ my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
+
push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
}
} elsif ($deviceid =~ m/^(net)(\d+)$/) {
- return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
+ return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
- my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
- my $use_old_bios_files = undef;
- ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
+ my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
+ my $use_old_bios_files = undef;
+ ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
- my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
- qemu_deviceadd($vmid, $netdevicefull);
- eval { qemu_deviceaddverify($vmid, $deviceid); };
+ my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
+ qemu_deviceadd($vmid, $netdevicefull);
+ eval {
+ qemu_deviceaddverify($vmid, $deviceid);
+ qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
+ };
if (my $err = $@) {
eval { qemu_netdevdel($vmid, $deviceid); };
warn $@ if $@;
die $err;
- }
+ }
} elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
if ($conf->{ivshmem}) {
my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
+ # just delete it for now, VMs which have this already open do not
+ # are affected, but new VMs will get a separated one. If this
+ # becomes an issue we either add some sort of ref-counting or just
+ # add a "don't delete on stop" flag to the ivshmem format.
unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
}
});
}
+sub convert_iscsi_path {
+ my ($path) = @_;
+
+ if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
+ my $portal = $1;
+ my $target = $2;
+ my $lun = $3;
+
+ my $initiator_name = get_initiator_name();
+
+ return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
+ "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
+ }
+
+ die "cannot convert iscsi path '$path', unkown format\n";
+}
+
sub qemu_img_convert {
my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
my $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
+ my $src_is_iscsi = ($src_path =~ m|^iscsi://|);
+ my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
+
my $cmd = [];
push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
push @$cmd, '-T', 'none' if $src_scfg->{type} eq 'zfspool';
- push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
- if ($is_zero_initialized) {
+
+ if ($src_is_iscsi) {
+ push @$cmd, '--image-opts';
+ $src_path = convert_iscsi_path($src_path);
+ } else {
+ push @$cmd, '-f', $src_format;
+ }
+
+ if ($dst_is_iscsi) {
+ push @$cmd, '--target-image-opts';
+ $dst_path = convert_iscsi_path($dst_path);
+ } else {
+ push @$cmd, '-O', $dst_format;
+ }
+
+ push @$cmd, $src_path;
+
+ if (!$dst_is_iscsi && $is_zero_initialized) {
push @$cmd, "zeroinit:$dst_path";
} else {
push @$cmd, $dst_path;