[! use strict; use Socket; use PVE::pvecfg; use PVE::I18N; use PVE::ConfigServer; use PVE::HTMLTable; use PVE::HTMLDropDown; use PVE::HTMLForm; use PVE::HTMLGrid; use PVE::HTMLUtils; !] [- use strict; my $cinfo = $fdat{__cinfo}; my $out = ''; my $form = PVE::HTMLForm->new (\%fdat); my $conn = PVE::ConfigClient::connect ($udat{auth_cookie}); my $titles_add = { dir => __("Add Directory"), lvm => __("Add LVM Group"), nfs => __("Add NFS Share"), iscsi => __("Add ISCSI Target"), }; my $titles_edit = { dir => __("Edit Directory"), lvm => __("Edit LVM Group"), nfs => __("Edit NFS Share"), iscsi => __("Edit ISCSI Target"), }; my $typenames = { dir => 'Directory', nfs => 'NFS', iscsi => 'ISCSI', lvm => 'LVM', }; my $fnames = { storeid => __("Storage Name"), path => __("Directory"), basestore => __("Base Storage"), base => __("Base Volume"), server => __("Server"), portal => __("Portal"), target => __("Target"), export => __("Export"), vgname => __("Volume Group Name"), enable => __("Enable"), shared => __("Shared"), content => __("Content"), }; if ($udat{action}) { my ($storeid, $digest) = split (/:/, $fdat{aa}); eval { check_write_mode ($udat{AM}); if ($udat{action} eq 'delete') { $conn->storage_remove ($storeid, $digest); } elsif ($udat{action} eq 'enable') { $conn->storage_enable ($storeid, $digest); } elsif ($udat{action} eq 'disable') { $conn->storage_disable ($storeid, $digest); } }; if ($@) { $udat{popup_error} = $@; $udat{redirect} = $fdat{__uri}; return; } } if ($form->action eq 'scan') { eval { if ($fdat{type} eq 'nfs') { check_field ($fnames->{server}, $fdat{server}, 'NOTEMPTY', 'SERVER'); if (my $res = $conn->storage_scan_nfs($fdat{server})->result) { $fdat{scandata} = join (" ", sort keys %$res); } else { $udat{popup_info} = __("Found no exports"); } } elsif ($fdat{type} eq 'iscsi') { check_field ($fnames->{portal}, $fdat{portal}, 'NOTEMPTY', 'PORTAL'); if (my $res = $conn->storage_scan_iscsi($fdat{portal}, 1)->result) { $fdat{scandata} = join (" ", sort keys %$res); } else { $udat{popup_info} = __("Found no unused targets"); } } }; $udat{popup_error} = $@ if $@; } elsif ($form->action eq 'save') { eval { check_write_mode ($udat{AM}); if ($fdat{type} eq 'iscsi') { $fdat{content} = $fdat{usedev} ? 'images' : 'none'; } if ($fdat{edit} == 2) { my $storeid = $fdat{storeid}; my $type = $fdat{type}; check_field ($fnames->{storeid}, $storeid, 'NOTEMPTY'); die "unable to use reserved storage ID '$storeid'\n" if $storeid eq 'local'; PVE::Storage::parse_storage_id ($storeid); my $param = []; if ($fdat{type} eq 'dir') { push @$param, "--path", $fdat{path}; } elsif ($fdat{type} eq 'nfs') { my $server = check_field ($fnames->{server}, $fdat{server}, 'NOTEMPTY', 'SERVER'); check_field ($fnames->{export}, $fdat{export}, 'NOTEMPTY'); push @$param, "--server", $server; push @$param, "--export", $fdat{export}; } elsif ($fdat{type} eq 'lvm') { check_field ($fnames->{vgname}, $fdat{vgname}, 'NOTEMPTY'); push @$param, "--vgname", $fdat{vgname}; push @$param, "--base", $fdat{base} if $fdat{base}; } elsif ($fdat{type} eq 'iscsi') { my $portal = check_field ($fnames->{portal}, $fdat{portal}, 'NOTEMPTY', 'PORTAL'); check_field ($fnames->{target}, $fdat{target}, 'NOTEMPTY'); push @$param, "--portal", $portal; push @$param, "--target", $fdat{target}; } push @$param, "--disable", 1 if !$fdat{enable}; push @$param, "--shared", 1 if $fdat{shared}; push @$param, "--content", $fdat{content} || 'none'; $conn->storage_add ($storeid, $type, $param); } else { my ($storeid, $digest) = split (/:/, $fdat{aa}); my $param = []; push @$param, "--disable", $fdat{enable} ? 0 : 1 if defined ($fdat{enable}); push @$param, "--shared", $fdat{shared} ? 1 : 0 if defined ($fdat{shared}); push @$param, "--content", $fdat{content} || 'none'; if (scalar (@$param)) { $conn->storage_set ($storeid, $param, $digest); } } }; if ($@) { $udat{popup_error} = $@; } else { $fdat{edit} = undef; } } my $ststat = $conn->get_storage_status ()->result; my $stcfg = $ststat->{cfg}; my @sids = PVE::Storage::storage_ids ($stcfg); my $iscsi_ids; foreach my $storeid (@sids) { my $scfg = PVE::Storage::storage_config ($stcfg, $storeid); if ($scfg->{type} eq 'iscsi') { push @$iscsi_ids, $storeid; } } if ($fdat{edit}) { my $fw3 = PVE::HTMLGrid::get_width ('fw3') - 80; my $grid = PVE::HTMLGrid->new ('fw1', 'fw2', 80, "${fw3}:right", 'fw4'); my $d; my ($storeid, $digest) = split (/:/, $fdat{aa}); my $edit = 0; if ($fdat{edit} == 2) { $d = { type => $fdat{type}, shared => 0, disable => 0, content => { 'images' => 1 }, }; } else { $edit = 1; $d = PVE::Storage::storage_config ($stcfg, $storeid); } my $is_shared = $d->{type} eq 'nfs' || $d->{type} eq 'iscsi'; my $islocal = $storeid && $storeid eq 'local'; $out .= $form->create_header($fdat{__uri}); if (!defined ($fdat{enable})) { $fdat{enable} = !$d->{disable}; }; foreach my $key (qw (shared path vgname server export portal target base)) { if (!defined ($fdat{$key})) { $fdat{$key} = $d->{$key}; }; } if (!defined ($fdat{content})) { my @ca = keys %{$d->{content}}; if ($islocal) { $fdat{content} = join (' ', @ca); } else { $fdat{content} = $ca[0] || 'none'; } }; if (!defined ($fdat{usedev})) { $fdat{usedev} = defined ($d->{content}->{images}); } my $clist = []; my $valid_ctypes = PVE::Storage::valid_content_types ($d->{type}); push @$clist, [ 'images', __("Virtual Disks") ] if $valid_ctypes->{images}; push @$clist, [ 'iso', __("ISO Images") ] if $valid_ctypes->{iso}; push @$clist, [ 'rootdir', __("OpenVZ Containers") ] if $islocal && $valid_ctypes->{rootdir}; push @$clist, [ 'vztmpl', __("OpenVZ Templates") ] if $islocal && $valid_ctypes->{vztmpl}; push @$clist, [ 'backup', __("VZDump Backups") ] if !$islocal && $valid_ctypes->{backup}; my $csel; if ($islocal) { $csel = $form->create_element ('content', 'checkbox', $fdat{content}, [ 1, $clist]); } else { $csel = $form->create_element ('content', 'dropdown', $fdat{content}, $clist); } my @ca; my $el; if ($edit) { $el = $form->create_element ('storeid', 'rotext', $storeid); } else { $el = $form->create_element ('storeid', 'text', $fdat{storeid}); } $ca[0][0] = [ $fnames->{storeid} . ':', $el ]; if ($d->{type} eq 'dir') { my $el = $form->create_element ('path', $edit ? 'rotext' : 'text', $fdat{path}); $ca[1][0] = [ $fnames->{path} . ':', $el ]; } elsif ($d->{type} eq 'lvm') { my $ind = 1; my $el; if (!$edit) { my $bida = [ ['', "Existing volume groups"] ]; if ($iscsi_ids) { foreach my $sid (@$iscsi_ids) { push @$bida, [ $sid, "$sid ($typenames->{iscsi})" ]; } } $el = $form->create_element ('basestore', 'dynamicdropdown', $fdat{basestore}, $bida); $ca[$ind++][0] = [ $fnames->{basestore} . ':', $el ]; if ($fdat{basestore}) { my $tmp = $conn->storage_list_volumes ($fdat{basestore})->result; my $imagelist = PVE::HTMLUtils::storage_format_volume_list_iscsi ($stcfg, $tmp); $el = $form->create_element ('base', 'dropdown', $fdat{base}, $imagelist); $ca[$ind++][0] = [ $fnames->{base} . ':', $el ]; } } else { if ($fdat{base}) { $el = $form->create_element ('base', 'rotext', $fdat{base}); $ca[$ind++][0] = [ $fnames->{base} . ':', $el ]; } } if ($edit) { $el = $form->create_element ('vgname', 'rotext', $fdat{vgname}); } else { if ($fdat{basestore}) { $el = $form->create_element ('vgname', 'text', $fdat{vgname}); } else { my $tmp = $conn->storage_list_vgs ()->result; my $vglist = PVE::HTMLUtils::storage_format_vgs_list ($stcfg, $tmp); $el = $form->create_element ('vgname', 'dropdown', $fdat{vgname}, $vglist); } } $ca[$ind++][0] = [ $fnames->{vgname} . ':', $el ]; } elsif ($d->{type} eq 'nfs') { my $el = $form->create_element ('server', $edit ? 'rotext' : 'text', $fdat{server}); $ca[1][0] = [ $fnames->{server} . ':', $el ]; $ca[1][1] = $form->create_cmdbutton ('scan') if !$edit; if (!$edit && $fdat{scandata}) { $el = $form->create_element ('export', $edit ? 'rotext' : 'dropdown', $fdat{export}, [ split (/\s/, $fdat{scandata}) ]); } else { $el = $form->create_element ('export', $edit ? 'rotext' : 'text', $fdat{export}); } $ca[2][0] = [ $fnames->{export} . ':', $el ]; } elsif ($d->{type} eq 'iscsi') { my $el = $form->create_element ('portal', $edit ? 'rotext' : 'text', $fdat{portal}); $ca[1][0] = [ $fnames->{portal} . ':', $el ]; $ca[1][1] = $form->create_cmdbutton ('scan') if !$edit; if (!$edit && $fdat{scandata}) { $el = $form->create_element ('target', $edit ? 'rotext' : 'dropdown', $fdat{target}, [ split (/\s/, $fdat{scandata}) ]); } else { $el = $form->create_element ('target', $edit ? 'rotext' : 'text', $fdat{target}); } $ca[2][0] = [ $fnames->{target} . ':', $el ]; } else { die "unknown storage type '$d->{type}' $fdat{edit}"; } # common settings for all storage types my $ind = 0; $ca[$ind++][2] = [ $fnames->{enable} . ':', $form->create_element ('enable', $islocal ? 'robool' : 'bool', $fdat{enable}) ]; if (!$is_shared) { $ca[$ind++][2] = [ $fnames->{shared} . ':', $form->create_element ('shared',$islocal ? 'robool' : 'bool', $fdat{shared}) ]; } if ($d->{type} eq 'iscsi') { $el = $form->create_element ('usedev', 'bool', $fdat{usedev}); $ca[$ind++][2] = [ __("Use LUNs directly") . ':', $el ]; } else { $ca[$ind++][2] = [ $fnames->{content} . ':', $csel ]; } foreach my $row (@ca) { my @ea = @$row; $grid->add_row ($ea[0][0], $ea[0][1], $ea[1], $ea[2][0], $ea[2][1]); } my $html = $grid->html(); $html .= $form->create_element("edit", "hidden", $fdat{edit}); $html .= $form->create_element("type", "hidden", $d->{type}); $html .= $form->create_element("aa", "hidden", $fdat{aa}); $html .= $form->create_element("scandata", "hidden", $fdat{scandata}); $html .= "
"; $html .= $form->create_cmdbutton ('save'); my $title = $edit ? $titles_edit->{$d->{type}} : $titles_add->{$d->{type}}; $out .= PVE::HTMLUtils::create_statusframe (undef, $title, undef, $html); $out .= $form->create_footer(); print OUT $out; return; } if ($fdat{browse}) { my ($storeid, $digest) = split (/:/, $fdat{aa}); my $scfg = PVE::Storage::storage_config ($stcfg, $storeid, 1); if (!$scfg) { $udat{popup_error} = __("No such Storage ID '$storeid'"); } elsif ($scfg->{disable}) { $udat{popup_error} = __("Storage '$storeid' is disabled"); } else { print OUT sprintf '

' . __("Content of Storage '%s'") . '


', $storeid; if ($scfg->{type} eq 'iscsi') { my $vlist = $conn->storage_list_volumes ($storeid)->result; my $table = PVE::HTMLTable->new ([]); my @header = ('1', '590px', __('Volume ID'), '1', '50px', 'LUN', '1', '100px', __('Size (GB)'), ); $table->add_headline (\@header); my $found; PVE::Storage::foreach_volid ($vlist, sub { my ($volid, $sid, $volname, $info) = @_; my $size = sprintf "%.2f", $info->{size} / (1024*1024); $table->add_row ('', $volid, $info->{lun}, $size); $found = 1; }); $table->add_row ('', __("no entries"), '', '') if !$found; my $html = PVE::HTMLUtils::create_statusframe ('', __("ISCSI LUN list") , undef, $table->out_table()); print OUT $html; return; } if ($scfg->{content}->{images}) { my $vlist = $conn->storage_list_volumes ($storeid)->result; my $table = PVE::HTMLTable->new ([]); my @header = ('1', '490px', __('Volume ID'), '1', '50px', 'VMID', '1', '100px', __('Size (GB)'), + '1', '100px', __('Used (GB)'), ); $table->add_headline (\@header); my $found; PVE::Storage::foreach_volid ($vlist, sub { my ($volid, $sid, $volname, $info) = @_; my $size = sprintf "%.2f", $info->{size} / (1024*1024); my $used = $info->{used} ? sprintf "%.2f", $info->{used} / (1024*1024) : '-'; $table->add_row ('', $volid, $info->{vmid}, $size, $used); $found = 1; }); $table->add_row ('', __("no entries"), '', '') if !$found; my $html = PVE::HTMLUtils::create_statusframe ('', __("Virtual Disks"), undef, $table->out_table()); $html .= '
'; print OUT $html; } if ($scfg->{content}->{iso}) { my $vlist = $conn->storage_list_iso ($storeid)->result; my $table = PVE::HTMLTable->new ([]); my @header = ('1', '740px', __('Volume ID')); $table->add_headline (\@header); my $found; PVE::Storage::foreach_volid ($vlist, sub { my ($volid, $sid, $volname, $info) = @_; $table->add_row ('', $volid); $found = 1; }); $table->add_row ('', __("no entries"), '', '') if !$found; my $html = PVE::HTMLUtils::create_statusframe ('', __("ISO Images"), undef, $table->out_table()); $html .= '
'; print OUT $html; } if ($scfg->{content}->{vztmpl}) { my $vlist = $conn->storage_list_vztmpl ($storeid)->result; my $table = PVE::HTMLTable->new ([]); my @header = ('1', '740px', __('Volume ID')); $table->add_headline (\@header); my $found; PVE::Storage::foreach_volid ($vlist, sub { my ($volid, $sid, $volname, $info) = @_; $table->add_row ('', $volid); $found = 1; }); $table->add_row ('', __("no entries"), '', '') if !$found; my $html = PVE::HTMLUtils::create_statusframe ('', __("OpenVZ Templates"), undef, $table->out_table()); $html .= '
'; print OUT $html; } if ($scfg->{content}->{backup}) { my $vlist = $conn->storage_list_backups ($storeid)->result; my $table = PVE::HTMLTable->new ([]); my @header = ('1', '640px', __('Volume ID'), '1', '100px', __('Size (GB)')); $table->add_headline (\@header); my $found; PVE::Storage::foreach_volid ($vlist, sub { my ($volid, $sid, $volname, $info) = @_; my $size = sprintf "%.2f", $info->{size} / (1024*1024*1024); $table->add_row ('', $volid, $size); $found = 1; }); $table->add_row ('', __("no entries"), '', '') if !$found; my $html = PVE::HTMLUtils::create_statusframe ('', __("VZDump Backups"), undef, $table->out_table()); $html .= '
'; print OUT $html; } return; } } my $table = PVE::HTMLTable->new ([]); my @header = ('1', '20px', ' ', '1', '200px', $fnames->{storeid}, '1', '70px', __('Type'), '1', '50px', __('Enabled'), '1', '50px', __('Active'), '1', '50px', __('Shared'), '1', '100px', __('Used (GB)'), '1', '100px', __('Capacity (GB)'), '1', '100px', ' ', ); $table->add_headline (\@header); my $ddown = PVE::HTMLDropDown->new (); $ddown->add_item ("menu0","?edit=2&type=iscsi", $titles_add->{iscsi}); $ddown->add_item ("menu0","?edit=2&type=nfs", $titles_add->{nfs}); $ddown->add_item ("menu0","?edit=2&type=lvm", $titles_add->{lvm}); $ddown->add_item ("menu0","?edit=2&type=dir", $titles_add->{dir}); $ddown->add_item ("menu1","?edit=1", __("Edit")); $ddown->add_item ("menu1","?browse=1", __("Browse")); $ddown->add_item ("menu1","?action=delete", __("Delete")); $ddown->add_item ("menu1","?action=enable", __("Enable")); $ddown->add_item ("menu1","?action=disable", __("Disable")); $ddown->add_item ("menu2","?edit=1", __("Edit")); $ddown->add_item ("menu2","?browse=1", __("Browse")); $out .= "

" . $ddown->out_symbol("menu0", "iarrdown") . " " . __("Storage List") . "


"; $out .= $ddown->out_dropdown_menu("menu0"); $out .= $ddown->out_dropdown_menu("menu1"); $out .= $ddown->out_dropdown_menu("menu2"); foreach my $storeid (@sids) { my $scfg = PVE::Storage::storage_config ($stcfg, $storeid); my $info = $ststat->{info}->{$storeid}; my $menu = $ddown->out_symbol ($storeid eq 'local' ? "menu2" : "menu1", "","&aa=$storeid:$stcfg->{digest}"); $table->set_row_link ("?browse=1&aa=$storeid:$stcfg->{digest}"); my $diskbar = PVE::HTMLUtils::create_bar (100, $info->{avail} , $info->{used}); my $fused = sprintf ("%0.2f", $info->{used} / (1024*1024)); my $favail = sprintf ("%0.2f", $info->{avail} / (1024*1024)); if ($scfg->{type} eq 'iscsi') { $fused = $favail = $diskbar = 'n/a'; } $table->add_row ('', $menu, $storeid, $typenames->{$scfg->{type}}, $info->{disable} ? __('No') : __('Yes'), $info->{active} ? __('Yes') : __('No'), $scfg->{shared} ? __('Yes') : __('No'), $fused, $favail, $diskbar); } $out .= $table->out_table(); print OUT $out; -]