[!
use strict;
use PVE::pvecfg;
use PVE::I18N;
use PVE::ConfigServer;
use PVE::HTMLTable;
use PVE::Config;
use PVE::Cluster;
use PVE::HTMLForm;
use PVE::HTMLUtils;
use PVE::QemuServer;
!]
[-
use strict;
sub html_table_line {
my ($v1, $v2, $v3, $v4) = @_;
$v1 = " " if !$v1;
$v2 = " " if !$v2;
$v3 = " " if !$v3;
$v4 = " " if !$v4;
my $html = '
';
$html .= "$v1 | $v2 | ";
$html .= " | $v3 | $v4 |
\n";
return $html;
}
my @disks = PVE::QemuServer::disknames();
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;
}
my $form = PVE::HTMLForm->new (\%fdat);
my $out = '';
my $cinfo = $fdat{__cinfo};
my $veid = $fdat{veid};
my $cid = $fdat{cid};
my $vminfo = PVE::Cluster::load_vmconfig ($cinfo, $cid, $veid, 'qemu');
my $status = $vminfo->{vzlist}->{"VEID_$veid"}->{status};
my $vmconf = $vminfo->{config};
my $ni = $vminfo->{ni};
my $medialist = PVE::Config::get_media_list();
$medialist = [ 'none', @$medialist ];
if ($udat{action}) {
my $data = $fdat{aa};
if (($udat{action} eq 'deldisk') || ($udat{action} eq 'delcdrom')) {
eval {
my $settings = { $data => '' };
my $conn = PVE::ConfigClient::connect ();
$conn->vmconfig_set ($udat{auth_username}, $cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
}
} elsif (($udat{action} eq 'delunused')) {
eval {
my $conn = PVE::ConfigClient::connect ();
$conn->qemu_unlink_disk ($udat{auth_username}, $cid, $veid, $data)->result;
};
if ($@) {
$udat{popup_error} = $@;
}
} elsif ($udat{action} eq 'delnic') {
foreach my $i (0 .. 9, 'u') {
my $vlan = "vlan$i";
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 {
my $conn = PVE::ConfigClient::connect ();
$conn->vmconfig_set ($udat{auth_username}, $cid, $veid, 'qemu', $settings)->result;
};
$udat{popup_error} = $@ if $@;
last;
}
}
}
print OUT $out;
return;
}
if ($form->action =~ m/^setcdrom-(\S+)/) {
my $dev = $1;
my $value = $fdat{"cdrom-$dev"};
my $settings = { $dev => $value };
eval {
my $conn = PVE::ConfigClient::connect ();
$conn->vmconfig_setcdrom ($udat{auth_username}, $cid, $veid, $settings)->result;
};
$udat{popup_error} = $@ if $@;
} 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 {
my $conn = PVE::ConfigClient::connect ();
$conn->vmconfig_set ($udat{auth_username}, $cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
}
}
} 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 {
my $conn = PVE::ConfigClient::connect ();
$conn->vmconfig_set ($udat{auth_username}, $cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
}
}
} else {
delete ($fdat{edit});
}
} elsif ($form->action eq 'create') {
if ($fdat{itype} eq 'nic') {
my $vlan = $fdat{bridge} || 'vlan0';
my $cc = $vmconf->{$vlan};
my $mac = PVE::QemuServer::random_ether_addr();
my $network = "$fdat{model}=$mac";
$cc = $cc ? "$cc,$network" : $network;
my $settings = { $vlan => $cc };
eval {
my $conn = PVE::ConfigClient::connect ();
$conn->vmconfig_set ($udat{auth_username}, $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 {
# fixme: check size
my $settings = { $fdat{device} => $fdat{hdsize} };
my $conn = PVE::ConfigClient::connect ();
$conn->vmconfig_set ($udat{auth_username}, $cid, $veid, 'qemu', $settings)->result;
};
if ($@) {
$udat{popup_error} = $@;
} else {
$udat{redirect} = $fdat{__uri};
}
}
} else {
delete ($fdat{edit});
}
}
if ($fdat{edit} == 2) {
$out .= $form->create_header($fdat{__uri});
if ($fdat{itype} eq 'disk') {
my $devsel1 = device_list ($vmconf, $fdat{disktype} || 'ide');
my $html = '';
my $dtypes = [['ide', 'IDE'], ['scsi', 'SCSI'], ['virtio', 'VIRTIO']];
$html .= html_table_line (__("Disk space") . ' (GB):',
$form->create_element ('hdsize', 'text', $fdat{hdsize} || 32),
__("Bus") . ':',
$form->create_element ('disktype', 'dynamicdropdown',
$fdat{disktype}, $dtypes));
$html .= html_table_line ('', '',
__("Device") . ':',
$form->create_element ('device', 'dropdown',
$fdat{device}, $devsel1));
$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;
foreach my $ds (keys %$di) {
next if $ds !~ m/^unused\d+$/;
push @$unused, $di->{$ds};
push @$ddown, [ $di->{$ds}->{file}, "$di->{$ds}->{file} ($di->{$ds}->{disksize}GB)" ];
}
if ($unused) {
$out .= "
\n";
my $devsel2 = device_list ($vmconf, $fdat{unuseddisktype} || 'ide');
my $html = '';
$html .= html_table_line (__("Existing Disks"),
$form->create_element ('unused', 'dropdown', $fdat{unused}, $ddown),
__("Bus") . ':',
$form->create_element ('unuseddisktype', 'dynamicdropdown',
$fdat{unuseddisktype}, $dtypes));
$html .= html_table_line ('', '',
__("Device"),
$form->create_element ('unuseddevice', 'dropdown',
$fdat{unuseddevice}, $devsel2));
$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']];
my $html = '';
$html .= html_table_line (__("CDROM") . ':',
$form->create_element ('cdrom', 'dropdown',
$fdat{cdrom} || 'none', $medialist),
__("Bus") . ':',
$form->create_element ('disktype', 'dynamicdropdown',
$fdat{disktype}, $dtypes));
$html .= html_table_line ('', '',
__("Device"),
$form->create_element ('device', 'dropdown',
$fdat{device}, $devsel1));
$html .= "
" . $form->create_cmdbutton ('add');
$out .= PVE::HTMLUtils::create_statusframe (undef, __("Add a CD-ROM drive"), undef, $html);
} elsif ($fdat{itype} eq 'nic') {
my $html = "";
my $nics = PVE::QemuServer::nic_models ();
my $bridges = PVE::Utils::get_bridges ();
my $brg;
foreach my $bn (@$bridges) {
if ($bn =~ m/^vmbr([0-9])$/) {
push @$brg, [ "vlan$1", "vmbr$1" ];
}
}
push @$brg, [ "vlanu", "NAT (User Mode Network)" ];
$html .= html_table_line (__("Model"),
$form->create_element ('model', 'dropdown',
$fdat{model}, $nics),
__("Bridge") . ':',
$form->create_element ('bridge', 'dropdown', 'vmbr0', $brg));
$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_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', "?action=delcdrom", __('Delete'));
$out .= $ddown->out_dropdown_menu ("menu0");
$out .= "" . $ddown->out_symbol("menu0", "iarrdown") .
" " . __("Hardware device list for VM $veid") . "
";
$out .= $ddown->out_dropdown_menu ("menudisk");
$out .= $ddown->out_dropdown_menu ("menuunused");
$out .= $ddown->out_dropdown_menu ("menunic");
$out .= $ddown->out_dropdown_menu ("menucdrom");
my $header_disk = ['1', '20px', ' ',
'1', '10px', ' ',
'1', '100px', __("Bus"),
'1', '100px', __('Device'),
'1', '100px', __('Size'),
'1', '360px', __("File name")];
my $table = PVE::HTMLTable->new ([]);
$table->add_headline ($header_disk);
my $found = 0;
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);
my $size = '-';
if ($vmconf->{diskinfo} && $vmconf->{diskinfo}->{$ds}) {
$size = $vmconf->{diskinfo}->{$ds}->{disksize};
}
my $devinfo = PVE::QemuServer::disk_devive_info ($ds);
my $menu = $ddown->out_symbol ('menudisk', '', "&aa=$ds");
$table->add_row ('' ,$menu, '', uc($devinfo->{bus}), $devinfo->{desc}, "${size}GB", $disk->{file});
$found = 1;
}
my $html;
if ($found) {
$html = $table->out_table ();
}
my $header_unused = ['1', '20px', ' ',
'1', '10px', ' ',
'1', '100px', __('Size'),
'1', '560px', __("Unused disk images"),
];
$table = PVE::HTMLTable->new ([]);
$table->add_headline ($header_unused);
my $ufound = 0;
my $uhtml = "
";
my $di = $vmconf->{diskinfo} || {};
foreach my $ds (keys %$di) {
next if $ds !~ m/^unused\d+$/;
$ufound = 1;
my $file = $di->{$ds}->{file};
my $menu = $ddown->out_symbol ('menuunused', '', "&aa=$file");
$table->add_row ('' ,$menu, '', "$di->{$ds}->{disksize}GB", $file);
}
$uhtml .= $table->out_table ();
$html .= $uhtml if $ufound;
if (!$found && !$ufound) {
$html = "no devices";
}
$out .= PVE::HTMLUtils::create_statusframe (undef, __("Hard disks"), undef, $html);
my $header_cdrom = ['1', '20px', ' ',
'1', '10px', ' ',
'1', '100px', __("Bus"),
'1', '100px', __('Device'),
'1', '100px', ' ',
'1', '300px', __("Media"),
'1', '60px', ' ',
];
my $table = PVE::HTMLTable->new ([]);
$table->add_headline ($header_cdrom);
$found = 0;
foreach my $ds (@disks) {
next if !defined ($vmconf->{$ds});
my $disk = PVE::QemuServer::parse_drive ($ds, $vmconf->{$ds});
next if !PVE::QemuServer::drive_is_cdrom ($disk);
my $menu = $ddown->out_symbol ('menucdrom', '', "&aa=$ds");
my $devinfo = PVE::QemuServer::disk_devive_info ($ds);
my $key = "cdrom-$ds";
my $v = defined ($fdat{$key}) ? $fdat{$key} : $disk->{file} || 'none';
my $el = $form->create_element ($key, 'dropdown', $v, $medialist, 300);
my $cmd = $form->create_cmdbutton ("setcdrom-$ds", __('apply'));
$table->add_row ('' ,$menu, '', uc($devinfo->{bus}), $devinfo->{desc}, '', $el, $cmd);
$found = 1;
}
if ($found) {
$html = $table->out_table ();
} else {
$html = "no devices";
}
$out .= '
';
$out .= PVE::HTMLUtils::create_statusframe (undef, __("CD-ROM drives"), undef, $html);
my $header_nic = ['1', '20px', ' ',
'1', '10px', ' ',
'1', '100px', __("Model"),
'1', '100px', __('Bridge'),
'1', '100px', ' ',
'1', '360px', __("MAC address")];
my $table = PVE::HTMLTable->new ([]);
$table->add_headline ($header_nic);
$found = 0;
foreach my $id (0 .. 9, 'u') {
next if !defined ($vmconf->{"vlan$id"});
my $net = PVE::QemuServer::parse_vlan ($vmconf->{"vlan$id"});
next if !$net || !$net->{nics};
my $brname = $id eq 'u' ? "NAT" : "vmbr$id";
foreach my $nic (sort { $a->{model} cmp $b->{model} } @{$net->{nics}}) {
next if !$nic->{model} || !$nic->{macaddr};
my $menu = $ddown->out_symbol ('menunic', '', "&aa=$nic->{macaddr}");
$table->add_row ('' ,$menu, '', $nic->{model}, $brname, '', $nic->{macaddr});
$found = 1;
}
}
if ($found) {
$html = $table->out_table ();
} else {
$html = "no devices";
}
$out .= '
';
$out .= PVE::HTMLUtils::create_statusframe (undef, __("Ethernet devices"), undef, $html);
$out .= $form->create_footer();
print OUT $out;
return;
-]