Inspired by danboid's post I have created some custom scripts to add ZFS support to virtualmin. The before script serverzfs.pl will create a zfs dataset under your home pool and set the quota from the plan there is one. It will handle change operations as well although I have uncovered a bug wherein if a virtual server has it's plan changed both $VIRTUALSERVER_NEWSERVER_QUOTA and VIRTUALSERVER_QUOTA are set to the previous plans values. If you then go back and do a second edit (like changing the description) the new plans quota values will be sent. The "after" script will destroy the zfs dataset when a server is being deleted or moved.
The script defaults to assuming your /home is under 'rpool' as that's how the Debian HOWTO had me set it up, I've seen other guides use 'tank' so if that's your setup change the variable on line 3 (in danboids setup it would be 'zhome'). I'm also using $VIRTUALSERVER_HOME instead of
/home/$VIRTUALSERVER_USER as this should be more portable.
serverzfs.pl
#!/usr/bin/env perl
my $pool = 'rpool'; # Often 'tank'
my $quota = 'quota'; # set 'refquota' to not count snapshots/clones
my $zfs = '/usr/sbin/zfs';
my $verbose = 1; # Report successful operations
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'CREATE_DOMAIN') {
&make_dir("$ENV{'VIRTUALSERVER_HOME'}");
if ($ENV{'VIRTUALSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_HOME'},$ENV{'VIRTUALSERVER_QUOTA'});
}
}
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'MODIFY_DOMAIN') {
if ($ENV{'VIRTUALSERVER_HOME'} ne $ENV{'VIRTUALSERVER_NEWSERVER_HOME'}) {
&make_dir($ENV{'VIRTUALSERVER_NEWSERVER_HOME'});
if ($ENV{'VIRTUALSERVER_NEWSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_NEWSERVER_HOME'},$ENV{'VIRTUALSERVER_NEWSERVER_QUOTA'});
}
}
if ($ENV{'VIRTUALSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_HOME'},$ENV{'VIRTUALSERVER_QUOTA'});
} else {
&set_quota($ENV{'VIRTUALSERVER_HOME'},'none');
}
}
sub make_dir {
my $dset = $pool . shift;
if ($verbose) { print "Creating $dset dataset ..<br>\n"; }
my $code = system("$zfs create $dset");
if ($code) { die "Failed to create $dset 😢 $!\n"; }
else { print ".. done 😀<br>\n" unless (! $verbose); }
}
sub set_quota {
my $dset = $pool . shift;
my $limit = shift; my $size = '<strong>none</strong>';
if ($limit ne 'none') {
my $limit = $limit * 1024;
my $size = &prettyBytes($limit);
}
if ($verbose) { print "<br>Setting quota for $dset to $size .. <br>\n"; }
my $code = system("$zfs set $quota=$limit $dset");
if ($code) { die "Failed to set quota for $dset 😢 $!\n"; }
else { print ".. done 😀\n" unless (! $verbose); }
}
sub prettyBytes {
my $size = $_[0];
foreach ('b','kb','mb','gb','tb','pb')
{
return sprintf("%.2f",$size)."$_" if $size < 1024;
$size /= 1024;
}
}
serverzfs-after.pl
#!/usr/bin/env perl
my $pool = 'rpool'; # Often 'tank'
my $quota = 'quota'; # set 'refquota' to not count snapshots/clones
my $zfs = '/usr/sbin/zfs';
my $verbose = 1; # Report successful operations
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'MODIFY_DOMAIN') {
if ($ENV{'VIRTUALSERVER_NEWSERVER_HOME'}) {
&rm_dir($ENV{'VIRTUALSERVER_HOME'});
}
}
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'DELETE_DOMAIN') {
&rm_dir($ENV{'VIRTUALSERVER_HOME'});
}
sub rm_dir {
my $dset = $pool . shift;
if ($verbose) { print "Removing $dset dataset ..<br>\n"; }
my $code = system("$zfs destroy -r $dset");
if ($code) { die "Failed to remove $dset 😢 $!\n"; }
else { print ".. done 😀<br>\n" unless (! $verbose); }
}
I’d like to develop similar scripts for user creation but I’m stymied by the fact virtualmin is not offering quota settings in the add/edit user pages due to the fact it thinks the file system doesn’t support them. Is there an easy flag to switch to force webmin to show a quota setting on the user setup or would custom fields be the go?
Also if anyone has any tips on how to post source code without it being munged that would be appreciated. Apparently the <pre> tag means something different round these parts than everywhere else.
Well it worked better than pre but still interpreting html tags inside the code and removing indents. I’ll put up a download link when I get the user adding sorted.
You need a line feed for triple backticks to work. I’ve edited your post. (But, it looks like there’s some extra mess in there, I’m not sure what’s going on with the extra backticks and HTML markup. HTML doesn’t do anything in this forum.)
I’d gone through and added single backticks to all the lines of code that output HTML to stop it being marked up. They’ve been removed now and you can get a compilable script by cutting and pasting. I can assure you that html very much does do things on this forum.
There was a couple of bugs in the first two scripts but I’m unable to edit or delete them so reposting the latest version here. Unfortunately virtualmin’s custom scripts function is far too buggy to safely implement a similar feature for users. You can set a before/after script in webmin user handling but virtualmin only calls it AFTER the users home directory has been created and to make matters worse they behave differently in other ways. For example if moving a users home directory virtualmin will pass USERADMIN_HOME and USERADMIN_OLD_HOME but webmin will only pass USERADMIN_HOME with the new value and do you know what happens when you run zfs destroy -r pool/home<empty var>? Yup goodbye to your home partition and the snapshots that were supposed to save you from this kind of disaster. And as vanishingly small as the chances are that the virtualmin team will ever respond to bug reports and fix their product developing logic around the current misbehaviour invites further issues if a new version is released with different behaviour. I spent a few hours on Sunday going through the source code in the hopes of patching edit_user.cgi and save_user.cgi and it is some of the most incomprehensible perl you will ever see. At this point it’s my reluctant conclusion that the entire codebase needs to be forked/rewritten by someone with far more time and enthusiasm than I but I’ll post my latest before/after scripts below with the user code commented out in case it guides someone else’s efforts and there’s now a check for an empty var before running the destroy command so hopefully no more innocent home partitions need to die. Setting zfs-before and zfs-after as your virtualserver before/after scripts will get you a unique dataset and quota for each virtual server however so there’s that.
zfs-before
#!/usr/bin/env perl
########################### Variable Settings ##################################
my $pool = 'rpool'; # Often 'tank'
my $qtype = 'quota'; # set 'refquota' to not count snapshots/clones
my $zfs = '/usr/sbin/zfs';
my $verbose = 1; # Report successful operations
my $onegb = 1073741824;
my $quota = $onegb * 10; # Default user quota in bytes
######################### End of variable settings #############################
########################### Webmin User Handling ###############################
#if ($ENV{'SCRIPT_FILENAME'} eq '/usr/share/webmin/useradmin/save_user.cgi') { #webmin detected
#unless ($ENV{'USERADMIN_QUOTA'}) {
# if ($ENV{'USERADMIN_ZQUOTA'}) { $ENV{'USERADMIN_QUOTA'} = $ENV{'USERADMIN_ZQUOTA'}; }
# elsif ($quota) { $ENV{'USERADMIN_QUOTA'} = $quota; }
#}
#if ($ENV{'USERADMIN_ACTION'} eq 'CREATE_USER') {
# &make_dir($ENV{'USERADMIN_HOME'});
# if ($ENV{'USERADMIN_QUOTA'}) {
# &set_quota($ENV{'USERADMIN_HOME'},$ENV{'USERADMIN_QUOTA'});
# }
#}
#if ($ENV{'USERADMIN_ACTION'} eq 'MODIFY_USER') {
# if ($ENV{'USERADMIN_HOME'} ne $ENV{'USERADMIN_OLD_HOME'}) {
# &make_dir($ENV{'USERADMIN_HOME'});
# }
# if ($ENV{'USERADMIN_QUOTA'}) {
# &set_quota($ENV{'USERADMIN_HOME'},$ENV{'USERADMIN_QUOTA'});
# } else {
# &set_quota($ENV{'USERADMIN_HOME'},'none');
# }
#}
#} #webmin clause
######################## Virtualmin Server Handling ############################
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'CREATE_DOMAIN') {
&make_dir($ENV{'VIRTUALSERVER_HOME'});
if ($ENV{'VIRTUALSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_HOME'},$ENV{'VIRTUALSERVER_QUOTA'});
}
}
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'MODIFY_DOMAIN') {
if ($ENV{'VIRTUALSERVER_HOME'} ne $ENV{'VIRTUALSERVER_NEWSERVER_HOME'}) {
&make_dir($ENV{'VIRTUALSERVER_NEWSERVER_HOME'});
if ($ENV{'VIRTUALSERVER_NEWSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_NEWSERVER_HOME'},$ENV{'VIRTUALSERVER_NEWSERVER_QUOTA'});
}
}
if ($ENV{'VIRTUALSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_HOME'},$ENV{'VIRTUALSERVER_QUOTA'});
} else {
&set_quota($ENV{'VIRTUALSERVER_HOME'},'none');
}
}
############################## Common Functions ################################
sub make_dir {
my $dset = $pool . shift;
if ($verbose) { print "Creating $dset dataset ..<br>\n"; }
my $code = system("$zfs create $dset");
if ($code) { die "Failed to create $dset 😢 $!\n"; }
else { print ".. done 😀<br>\n" unless (! $verbose); }
}
sub set_quota {
my $dset = $pool . shift;
my $limit = shift; my $size = '<strong>none</strong>';
unless ($limit eq 'none') {
$limit = $limit * 1024;
$size = &prettyBytes($limit);
}
if ($verbose) { print "<br>Setting quota for $dset to $size .. <br>\n"; }
my $code = system("$zfs set $qtype=$limit $dset");
if ($code) { die "Failed to set quota for $dset 😢 $!\n"; }
else { print ".. done 😀\n" unless (! $verbose); }
}
sub prettyBytes {
my $size = $_[0];
foreach ('b','kb','mb','gb','tb','pb')
{
return sprintf("%.2f",$size)."$_" if $size < 1024;
$size /= 1024;
}
}
zfs-after
#!/usr/bin/env perl
########################### Variable Settings ##################################
my $pool = 'rpool'; # Often 'tank'
my $qtype = 'quota'; # set 'refquota' to not count snapshots/clones
my $zfs = '/usr/sbin/zfs';
my $verbose = 1; # Report successful operations
my $onegb = 1073741824;
my $quota = $onegb * 10; # Default user quota in bytes
######################### End of variable settings #############################
########################### Webmin User Handling ###############################
#if ($ENV{'SCRIPT_FILENAME'} eq '/usr/share/webmin/useradmin/save_user.cgi') { #webmin detected
#unless ($ENV{'USERADMIN_QUOTA'}) {
# if ($ENV{'USERADMIN_ZQUOTA'}) { $ENV{'USERADMIN_QUOTA'} = $ENV{'USERADMIN_ZQUOTA'}; }
# elsif ($quota) { $ENV{'USERADMIN_QUOTA'} = $quota; }
#}
#if ($ENV{'USERADMIN_ACTION'} eq 'CREATE_USER') {
# &make_dir($ENV{'USERADMIN_HOME'});
# if ($ENV{'USERADMIN_QUOTA'}) {
# &set_quota($ENV{'USERADMIN_HOME'},$ENV{'USERADMIN_QUOTA'});
# }
#}
#if ($ENV{'USERADMIN_ACTION'} eq 'MODIFY_USER') {
# if ($ENV{'USERADMIN_HOME'} ne $ENV{'USERADMIN_OLD_HOME'}) {
# &make_dir($ENV{'USERADMIN_HOME'});
# }
# if ($ENV{'USERADMIN_QUOTA'}) {
# &set_quota($ENV{'USERADMIN_HOME'},$ENV{'USERADMIN_QUOTA'});
# } else {
# &set_quota($ENV{'USERADMIN_HOME'},'none');
# }
#}
#} #webmin clause
######################## Virtualmin Server Handling ############################
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'CREATE_DOMAIN') {
&make_dir($ENV{'VIRTUALSERVER_HOME'});
if ($ENV{'VIRTUALSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_HOME'},$ENV{'VIRTUALSERVER_QUOTA'});
}
}
if ($ENV{'VIRTUALSERVER_ACTION'} eq 'MODIFY_DOMAIN') {
if ($ENV{'VIRTUALSERVER_HOME'} ne $ENV{'VIRTUALSERVER_NEWSERVER_HOME'}) {
&make_dir($ENV{'VIRTUALSERVER_NEWSERVER_HOME'});
if ($ENV{'VIRTUALSERVER_NEWSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_NEWSERVER_HOME'},$ENV{'VIRTUALSERVER_NEWSERVER_QUOTA'});
}
}
if ($ENV{'VIRTUALSERVER_QUOTA'}) {
&set_quota($ENV{'VIRTUALSERVER_HOME'},$ENV{'VIRTUALSERVER_QUOTA'});
} else {
&set_quota($ENV{'VIRTUALSERVER_HOME'},'none');
}
}
############################## Common Functions ################################
sub make_dir {
my $dset = $pool . shift;
if ($verbose) { print "Creating $dset dataset ..<br>\n"; }
my $code = system("$zfs create $dset");
if ($code) { die "Failed to create $dset 😢 $!\n"; }
else { print ".. done 😀<br>\n" unless (! $verbose); }
}
sub set_quota {
my $dset = $pool . shift;
my $limit = shift; my $size = '<strong>none</strong>';
unless ($limit eq 'none') {
$limit = $limit * 1024;
$size = &prettyBytes($limit);
}
if ($verbose) { print "<br>Setting quota for $dset to $size .. <br>\n"; }
my $code = system("$zfs set $qtype=$limit $dset");
if ($code) { die "Failed to set quota for $dset 😢 $!\n"; }
else { print ".. done 😀\n" unless (! $verbose); }
}
sub prettyBytes {
my $size = $_[0];
foreach ('b','kb','mb','gb','tb','pb')
{
return sprintf("%.2f",$size)."$_" if $size < 1024;
$size /= 1024;
}
}
Did you file a bug? This is the first time I’ve heard of such a problem.
We release updates every few weeks, usually with a combination of bugfixes and new features, as we have consistently done for two decades. I don’t know how you could come to the conclusion that we don’t fix bugs. But, we can’t fix bugs we don’t know about.
I couldn’t see any place on your site to report bugs. I’ve since taken a closer look and found the link to an external site tucked away at the bottom of the support page. Ok fine I’ll head there after this.
The disinterest you showed in the reported bug in the first paragraph of my original post vs. quibbling about the merits of html vs markdown.
The fact I haven’t had a single technical question posted to this forum answered whether it’s hooking into your procmail process or your user creation process. I get that paying customers have priority but I’m literally trying to add features that will benefit your entire user base. It seems like you have the time to post a new novel to the forum about how undermanned and underfunded virtualmin is every day but not 30 seconds to help me help you.
Where would you expect to find information about filing bugs, if not the Support page? (I am asking a genuine question. I don’t know where else we should put it to make it something one would find when looking for it.)
I’ll mention that our Github is linked from our homepage, too. I didn’t think it was hard to find how to participate.
You sound really hostile for reasons I don’t understand. I skim posts here looking for things I can help with quickly, as I only have a small amount of time to volunteer on Virtualmin. I don’t know anything about ZFS, so I didn’t think I could provide useful help here. I didn’t see mention of a bug. It’s tucked into the post, which I didn’t read in full, I just saw messy markup and tried to help sort that out. I do the best I can to help as many people as I can in the time I have to devote to the problem.
And, yes, paying customers do get more attention and time. I’m not going to apologize for that, it’s how Virtualmin continues to exist at all. But, we absolutely fix bugs, and usually quite fast.
Since you ask I expected to see it somewhere that I could actually see it. The first place I looked was along the top menu line of this site and the second was at the various forum categories. Not saying a forum category is a better choice than a github repository just that’s where I looked and it’s not all evident that you would have a github vs. gitlab or any other type of 3rd party hosting from what I’m seeing. Bear in mind that clicking on the upper-left logo from any page in the forum takes you to https://forum.virtualmin.com/not the home page thus once you’re inside forum.virtualmin.com effectively is the home page and support is not even linked to from the top menu bar. In fact here us the full sequence of steps I took to submit a bug report.
Click on Documentation
Read to end, see nothing
Click on Support
Read to end, click on “Github Issue Tracker”
I am still not on the issue tracker. I am at Virtualmin · GitHub from where I spend several minutes ascertaining which of the 49 public repositories is the correct one to submit the bug to.
sign in/create account get redirected to nowhere useful as per usual with github. Repeat steps 3-5
Submit a bug report
So to be clear you don’t understand why steps 1-7 weren’t immediately obvious to me and you also don’t understand why I had the expectation you would read the words right in front of you on a post you replied to and edited? And you are holding both misunderstandings in your head simultaneously? Is this inexplicable hostility in the room with us right now?
I’ll admit I was in a bit of a mood yesterday due to struggling with apache and fastcgi which was only necessary due to yet another bug with install scripts and nginx and losing emails due to a missing .spam folder in /home/._default_hostname … (and was mid-rant about what’s the point in reporting more bugs when a fix from yesterdays bug reports popped into my inbox so ok I’ll eat crow on the not fixing bugs claim).
Actually I was trying to say I hope you weren’t taking yesterday comments personally you just happened to be only person who responded. For the record my question was not pertaining to zfs but how to re-enable quota handling but in hindsight that’s not workable and I’ll need to add a new field or at least figure out what the existing quota handling does in webmin and it seems github is the place to pursue that and not these forums. I’ll just close by pointing out if potential contributors can’t come to these forums and get guidance on adding new features then you’ll get less contributors and new features than you otherwise would have and whomever’s job it is to spend time on this forum should probably take that into account moving forward.