[!
use strict;
use PVE::pvecfg;
use PVE::I18N;
use PVE::ConfigServer;
use PVE::HTMLTable;
use PVE::HTMLGrid;
use PVE::Config;
use PVE::Cluster;
use PVE::HTMLForm;
use PVE::HTMLUtils;
use PVE::QemuServer;
use PVE::Storage;
!]
[-
use strict;
my $out = '';
my $cinfo = $fdat{__cinfo};
my $veid = $fdat{veid};
my $cid = $fdat{cid};
my $conn = PVE::ConfigClient::connect ($udat{auth_cookie});
my $rconn = $conn;
if ($cid != $cinfo->{local}->{cid}) {
$rconn = PVE::ConfigClient::connect ($udat{auth_cookie}, $cinfo, $cid);
}
my $vminfo = $rconn->vmconfig ($veid, 'qemu')->result;
my $status = $vminfo->{vzlist}->{"VEID_$veid"}->{status};
my $vmconf = $vminfo->{config};
my $form = PVE::HTMLForm->new (\%fdat);
my $grid = PVE::HTMLGrid->new ('fw1', 'fw2', 'fw3:right', 'fw4');
my $stinfo = $rconn->storage_user_info ($veid)->result;
my $stcfg = $stinfo->{cfg};
my $imagelist = $stinfo->{imagelist};
my @disks = PVE::QemuServer::disknames();
my $used_volids = {};
foreach my $ds (@disks) {
next if !defined ($vmconf->{$ds});
my $disk = PVE::QemuServer::parse_drive ($ds, $vmconf->{$ds});
next if !$disk || PVE::QemuServer::drive_is_cdrom ($disk);
$used_volids->{$disk->{file}} = 1;
}
sub device_list {
my ($conf, $disktype) = @_;
my $devsel;
foreach my $ds (@disks) {
next if $ds !~ m/^$disktype\d+$/;
next if defined ($conf->{$ds});
my $devinfo = PVE::QemuServer::disk_devive_info ($ds);
push @$devsel, [ $ds, $devinfo->{desc} ];
}
$devsel = [[ '', sprintf (__("no %s devices available"), $disktype)]] if !$devsel;
return $devsel;
}
if ($udat{action}) {
my $data = $fdat{aa};
if (($udat{action} eq 'deldisk') || ($udat{action} eq 'delcdrom')) {
eval {
my $settings = { $data => '' };
$conn->vmconfig_set ($cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
}
} elsif (($udat{action} eq 'delunused')) {
eval {
$conn->qemu_unlink_disk ($cid, $veid, $data)->result;
};
if ($@) {
$udat{popup_error} = $@;
}
} elsif ($udat{action} eq 'delnic') {
foreach my $vlan (keys %$vmconf) {
next if $vlan !~ m/^vlan(\d+|u)$/;
my $cc = $vmconf->{$vlan};
next if !$cc;
my $net = PVE::QemuServer::parse_vlan ($cc);
next if !$net || !$net->{nics};
my $na = [];
my $found = 0;
foreach my $nic (@{$net->{nics}}) {
if (!$nic->{macaddr} || ($nic->{macaddr} ne $data)) {
push @$na, $nic;
} else {
$found = 1;
}
}
if ($found) {
$net->{nics} = $na;
$cc = PVE::QemuServer::print_vlan ($net);
my $settings = { $vlan => $cc };
eval {
$conn->vmconfig_set ($cid, $veid, 'qemu', $settings)->result;
};
$udat{popup_error} = $@ if $@;
last;
}
}
}
print OUT $out;
return;
}
if ($form->action eq 'setcdrom') {
if (!$fdat{device}) {
$udat{popup_error} = __("Please select a device");
} else {
eval {
$conn->vmconfig_setcdrom ($cid, $veid, $fdat{device}, $fdat{cdrom})->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
delete ($fdat{edit});
}
}
} elsif ($form->action eq 'add') {
if ($fdat{itype} eq 'disk') {
if (!$fdat{unuseddevice}) {
$udat{popup_error} = __("Please select a device");
} else {
my $settings = { $fdat{unuseddevice} => $fdat{unused} };
eval {
$conn->vmconfig_set ($cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
delete ($fdat{edit});
}
}
} elsif ($fdat{itype} eq 'cdrom') {
if (!$fdat{device}) {
$udat{popup_error} = __("Please select a device");
} else {
my $settings = { $fdat{device} => "$fdat{cdrom},media=cdrom" };
eval {
$conn->vmconfig_set ($cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
delete ($fdat{edit});
}
}
} else {
delete ($fdat{edit});
}
} elsif ($form->action eq 'create') {
if ($fdat{itype} eq 'nic') {
my $vlan = $fdat{bridge} || 'vlan0';
my $cc = $vmconf->{$vlan};
my $network = "$fdat{model}=$fdat{mac}";
$cc = $cc ? "$cc,$network" : $network;
my $settings = { $vlan => $cc };
eval {
check_field (__("MAC Address"), $fdat{mac}, 'NOTEMPTY', 'NOWHITESPACES', 'MAC');
$conn->vmconfig_set ($cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
}
} elsif ($fdat{itype} eq 'disk') {
if (!$fdat{device}) {
$udat{popup_error} = __("Please select a device");
} else {
eval {
check_field (__("Disk Storage"), $fdat{diskstore}, 'NOTEMPTY');
my $scfg = PVE::Storage::storage_config ($stcfg, $fdat{diskstore});
my $storagespec;
if ($scfg->{type} eq 'iscsi') {
check_field (__("ISCSI Device"), $fdat{image}, 'NOTEMPTY');
$storagespec = $fdat{image};
} else {
check_field (__("Disk space"), $fdat{hdsize}, 'NOTEMPTY', 'FLOAT');
$storagespec = "$fdat{diskstore}:$fdat{hdsize},format=$fdat{format}";
}
my $settings = { $fdat{device} => $storagespec};
$conn->vmconfig_set ($cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
}
}
} else {
delete ($fdat{edit});
}
}
if ($fdat{edit}) {
$out .= $form->create_header($fdat{__uri});
my $create = ($fdat{edit} == 2);
if ($fdat{itype} eq 'disk') {
my $devsel1 = device_list ($vmconf, $fdat{disktype} || 'ide');
my $dtypes = [['ide', 'IDE'], ['scsi', 'SCSI'], ['virtio', 'VIRTIO']];
$fdat{diskstore} = $stinfo->{images_default} if !$fdat{diskstore};
my $diskstorelist = PVE::HTMLUtils::storage_format_storage_list ($stinfo);
my ($defformat, $formatlist) = PVE::Storage::storage_default_format ($stcfg, $fdat{diskstore});
$fdat{format} = $defformat if !$fdat{format} || !grep {$_ eq $fdat{format}} @$formatlist;
$grid->add_row (__("Disk Storage") . ':',
$form->create_element ('diskstore', 'dynamicdropdown',
$fdat{diskstore}, $diskstorelist),
__("Image Format") . ':',
$form->create_element ('format', 'dropdown',
$fdat{format}, $formatlist));
my @ea;
my $scfg = PVE::Storage::storage_config ($stcfg, $fdat{diskstore});
if ($scfg && $scfg->{type} eq 'iscsi') {
my $tmp = $rconn->storage_list_volumes ($fdat{diskstore})->result;
my $iscsilist = PVE::HTMLUtils::storage_format_volume_list_iscsi ($stcfg, $tmp);
push @ea, __("ISCSI Devive") . ':',
$form->create_element ('image', 'dropdown', $fdat{image}, $iscsilist);
} else {
push @ea, __("Disk space") . ' (GB):',
$form->create_element ('hdsize', 'float', $fdat{hdsize} || 32);
}
$grid->add_row (@ea, __("Bus") . ':',
$form->create_element ('disktype', 'dynamicdropdown',
$fdat{disktype}, $dtypes));
$grid->add_row ('', '',
__("Device") . ':',
$form->create_element ('device', 'dropdown',
$fdat{device}, $devsel1));
my $html = $grid->html();
$html .= "
" . $form->create_cmdbutton ('create');
$out .= PVE::HTMLUtils::create_statusframe (undef, __("Create a new virtual disk"), undef, $html);
my $di = $vmconf->{diskinfo} || {};
my $unused;
my $ddown;
PVE::Storage::foreach_volid ($imagelist, sub {
my ($volid, $sid, $volname, $info) = @_;
return if $used_volids->{$volid};
$unused = 1;
my $size = int ($info->{size} / (1024*1024));
push @$ddown, [ $volid, "$volid (${size}GB)" ];
});
if ($unused) {
$out .= "
\n";
my $devsel2 = device_list ($vmconf, $fdat{unuseddisktype} || 'ide');
$grid->add_row (__("Existing Disks"),
$form->create_element ('unused', 'dropdown', $fdat{unused}, $ddown),
__("Bus") . ':',
$form->create_element ('unuseddisktype', 'dynamicdropdown',
$fdat{unuseddisktype}, $dtypes));
$grid->add_row ('', '',
__("Device"),
$form->create_element ('unuseddevice', 'dropdown',
$fdat{unuseddevice}, $devsel2));
my $html = $grid->html();
$html .= "
" . $form->create_cmdbutton ('add');
$out .= PVE::HTMLUtils::create_statusframe (undef, __("Use an existing virtual disk"), undef, $html);
}
} elsif ($fdat{itype} eq 'cdrom') {
my $devsel1 = device_list ($vmconf, $fdat{disktype} || 'ide');
my $dtypes = [['ide', 'IDE'], ['scsi', 'SCSI']];
if (!$create) {
my $ds = $fdat{aa};
die "no such cdrom drive '$ds'\n" if !($ds && $vmconf->{$ds});
$ds =~ m/^(ide|scsi|virtio)\d+$/ ||
die "got strange cdrom device '$ds'\n";
$fdat{disktype} = uc($1);
$fdat{device} = $ds;
if (my $disk = PVE::QemuServer::parse_drive ($ds, $vmconf->{$ds})) {
if ($disk->{file} eq 'none' || $disk->{file} eq 'cdrom') {
$fdat{cdrom} = $disk->{file} if !$fdat{cdrom};
} else {
my ($sid, $volname) = PVE::Storage::parse_volume_id ($disk->{file});
$fdat{isostore} = $sid if !$fdat{isostore};
$fdat{cdrom} = $disk->{file} if !$fdat{cdrom};
}
}
}
if (!$fdat{isostore} || !PVE::Storage::storage_config ($stcfg, $fdat{isostore}, 1)) {
$fdat{isostore} = $stinfo->{iso_default};
}
my $tmp = $rconn->storage_list_iso ($fdat{isostore})->result;
my $medialist = PVE::HTMLUtils::storage_format_iso_list ($stcfg, $tmp);
# symbolic name for cdrom, because cdrom path can be different at each node
unshift @$medialist, ['cdrom', 'cdrom device'];
unshift @$medialist, ['none', 'none (eject)'];
my $isostorelist = PVE::HTMLUtils::storage_format_storage_list($stinfo, 'iso');
$grid->add_row (__("ISO Storage") . ':',
$form->create_element ('isostore', 'dynamicdropdown',
$fdat{isostore}, $isostorelist),
__("Bus") . ':',
$form->create_element ('disktype', $create ? 'dynamicdropdown' : 'rotext',
$fdat{disktype}, $dtypes));
$grid->add_row (__("CDROM") . ':',
$form->create_element ('cdrom', 'dropdown',
$fdat{cdrom} || 'none', $medialist),
__("Device"),
$form->create_element ('device', $create ? 'dropdown' : 'rotext',
$fdat{device}, $devsel1));
my $html = $grid->html();
$html .= "
";
if ($create) {
$html .= $form->create_cmdbutton ('add');
} else {
$html .= $form->create_cmdbutton ('setcdrom', 'apply');
}
my $title = $create ? __("Add a CD-ROM drive") : __("Change CD-ROM");
$out .= PVE::HTMLUtils::create_statusframe (undef, $title, undef, $html);
} elsif ($fdat{itype} eq 'nic') {
my $nics = PVE::QemuServer::nic_models ();
$fdat{mac} = PVE::QemuServer::random_ether_addr() if !$fdat{mac};
my $bridges = PVE::Utils::get_bridges ();
my $brg;
foreach my $bn (@$bridges) {
if ($bn =~ m/^vmbr([0-9]{1,4})$/) {
push @$brg, [ "vlan$1", $bn ];
}
}
push @$brg, [ "vlanu", "NAT (User Mode Network)" ];
$grid->add_row (__("Model"),
$form->create_element ('model', 'dropdown',
$fdat{model}, $nics),
__("Bridge") . ':',
$form->create_element ('bridge', 'dropdown', 'vmbr0', $brg));
$grid->add_row ('', '',
__("MAC Address") . ':',
$form->create_element ('mac', 'text', $fdat{mac}));
my $html = $grid->html();
$html .= "
" . $form->create_cmdbutton ('create');
$out .= PVE::HTMLUtils::create_statusframe (undef, __("Add a network card"), undef, $html);
}
$out .= $form->create_element("edit", "hidden", $fdat{edit});
$out .= $form->create_element("itype", "hidden", $fdat{itype});
$out .= $form->create_element("aa", "hidden", $fdat{aa}) if !$create;
$out .= $form->create_footer();
print OUT $out;
return;
}
$out .= $form->create_header($fdat{__uri});
my $ddown = PVE::HTMLDropDown->new ();
$ddown->add_item ("menu0", "?itype=disk&edit=2", __("Add a hard disk"));
$ddown->add_item ("menu0", "?itype=nic&edit=2", __("Add an ethernet device"));
$ddown->add_item ("menu0", "?itype=cdrom&edit=2", __("Add a CD-ROM drive"));
$ddown->add_item ('menudisk', "?action=deldisk", __('Delete'));
$ddown->add_item ('menuunused', "?action=delunused", __('Delete from disk'));
$ddown->add_item ('menunic', "?action=delnic", __('Delete'));
$ddown->add_item ('menucdrom', "?itype=cdrom&edit=1", __('Edit'));
$ddown->add_item ('menucdrom', "?action=delcdrom", __('Delete'));
$out .= $ddown->out_dropdown_menu ("menu0");
$out .= "