Commit 054522cf authored by Mike Hibler's avatar Mike Hibler

Assorted changes.

Add wait option (-w). Check for lots of things that could have occured
while waiting and abort if such things happened (since any number of things
could have happened to the lease while you slept).

Permit state transtions that alloc/delloc resources if -R is specified.
Add -U option to forcibly unlock a lease (if it somehow got left locked).
parent 50d257d4
......@@ -33,19 +33,22 @@ use Date::Parse;
#
sub usage()
{
print STDERR "Usage: modlease [-hd] [-s state] [-e expire] [-l last-used] [-a key=value] [-d key] name\n";
print STDERR "Usage: modlease [-hdRU] [-w time] [-s state] [-e expire] [-l last-used] [-a key=value] [-d key] name\n";
print STDERR " -h This message\n";
print STDERR " -d Print additional debug info\n";
print STDERR " -R Permit resource alloc/dealloc to occur on state changes\n";
print STDERR " -U Unlock the lease (do not do this unless you know what you are doing!)\n";
print STDERR " -w time Try for up to time seconds to lock lease (0 means forever)\n";
print STDERR " -s state Update the state\n";
print STDERR " -e date Update the expiration date\n";
print STDERR " -l date Update the last used date ('now' for current time)\n";
print STDERR " -e date Update the expiration date ('now' for current time)\n";
print STDERR " -l date Update the last used date ('now' for current time, '0' for never)\n";
print STDERR " -a key=val Add or update attribute 'key' with value 'val'\n";
print STDERR " -r key Remove attribute 'key'\n";
print STDERR " name Name of lease (of form <pid>/<id>)\n";
exit(-1);
}
my $optlist = "dhs:e:l:a:r:";
my $optlist = "dhRUw:s:e:l:a:r:";
my $debug = 0;
my $pid;
my $state;
......@@ -56,6 +59,9 @@ my $delattr;
my $lname;
my $now = time();
my $lease;
my $waittime;
my $doresources = 0;
my $dounlock = 0;
# Protos
sub fatal($);
......@@ -99,6 +105,12 @@ if (defined($options{h})) {
if (defined($options{d})) {
$debug++;
}
if (defined($options{R})) {
$doresources = 1;
}
if (defined($options{U})) {
$dounlock = 1;
}
if (defined($options{s})) {
$state = $options{s};
}
......@@ -134,8 +146,14 @@ if (defined($options{r})) {
fatal("Malformed attribute name '$delattr'.");
}
}
if (defined($options{w})) {
$waittime = $options{w};
if ($waittime !~ /^\d+$/) {
fatal("Wait time must be >= 0.");
}
}
if (!($state || $expire || defined($lastused) || $addattr || $delattr)) {
if (!($state || $expire || defined($lastused) || $addattr || $delattr || $dounlock)) {
print STDERR "Must specify SOME action!\n";
usage();
}
......@@ -153,7 +171,10 @@ if ($lname =~ /^([-\w]+)\/([-\w]+)$/) {
fatal("Lease name $lname not in the form <pid>/<lname>.");
}
# XXX right now, must be admin
#
# XXX right now there are no user-modifiable attributes.
# Maybe we could let them manipulate attributes, but we don't right now.
#
if (!TBAdmin()) {
fatal("Only admins can modify leases right now.");
}
......@@ -189,38 +210,143 @@ if (!$lease->AccessCheck($this_user, LEASE_ACCESS_MODIFY())) {
fatal("$pid/$lname: you are not allowed to modify lease.");
}
#
# Unlock lease.
# XXX This should only be done if something blew up and left the
# lease locked.
#
if ($dounlock) {
if ($lease->Lock()) {
my $lpid = $lease->lockpid();
if ($lease->Unlock()) {
fatal("$pid/$lname: could not force unlock, lock held by pid $lpid");
} else {
print "$pid/$lname: forced lease unlock, was held by pid $lpid\n";
}
} else {
$lease->Unlock();
print "$pid/$lname: lock not held\n";
}
exit(0);
}
#
# Lock the lease while we change it.
# If it is already locked, someone else is doing something to it.
#
if ($lease->Lock()) {
fatal("$pid/$lname: could not acquire lock, try again later.");
if (!defined($waittime)) {
fatal("$pid/$lname: could not acquire lock, try again with -w")
if ($lease->Lock());
}
#
# Check that characteristics of the lease that we are modifying do
# not change while we are waiting for the lock. If they do, we abort.
# XXX this is an epic amount of work for probably very little value!
#
else {
my $ostate = $lease->state();
my $oexpire = $lease->expiration();
my $olused = $lease->last_used();
my $oattrs = $lease->GetAttributes();
fatal("$pid/$lname: could not acquire lock after $waittime seconds")
if ($lease->WaitLock($waittime, 1));
my $nstate = $lease->state();
my $nexpire = $lease->expiration();
my $nlused = $lease->last_used();
my $nattrs = $lease->GetAttributes();
if ($state && ($ostate ne $nstate)) {
fatal("$pid/$lname: lease state changed ".
"while waiting for the lock ($ostate => $nstate).");
}
if ($expire && ($oexpire != $nexpire)) {
fatal("$pid/$lname: lease expiration changed ".
"while waiting for the lock ($oexpire => $nexpire).");
}
if (defined($lastused) && ($olused != $nlused)) {
fatal("$pid/$lname: lease last_used changed ".
"while waiting for the lock ($olused => $nlused).");
}
if ($addattr || $delattr) {
foreach my $a (keys %$oattrs) {
if (!exists($nattrs->{$a}) || ($oattrs->{$a} ne $nattrs->{$a})) {
fatal("$pid/$lname: lease attributes changed ".
"while waiting for the lock.");
}
}
foreach my $a (keys %$nattrs) {
if (!exists($oattrs->{$a})) {
fatal("$pid/$lname: lease attributes changed ".
"while waiting for the lock.");
}
}
}
}
#
# Handle state. Ensure that this is a valid state transition.
#
# Handle state. The transition from unapproved->* is special and must
# be done via approvelease. It implies allocation of storage for dataset
# leases. We also do not mess with the lease if it is initializing.
# N.B.: the transition from/to unapproved is special since it implies
# allocation or deallocation of resources. We may want to rethink the
# ability to alloc/dealloc here as it is not obvious that modifying a
# lease should have such severe side-effects.
#
if ($state) {
my $curstate = $lease->state();
if ($curstate eq "unapproved") {
fatal("$pid/$lname: must be approved before other state changes can be made.");
if ($state ne $curstate) {
if (!$lease->ValidTransition($state)) {
fatal("$pid/$lname: cannot transtion from $curstate to $state.");
}
if ($curstate eq "initializing") {
fatal("$pid/$lname: in transition, try later.");
if ($curstate eq LEASE_STATE_UNAPPROVED()) {
if ($doresources) {
if ($lease->AllocResources($state)) {
fatal("$pid/$lname: could not allocate resources ".
"when moving from unapproved.");
}
} else {
fatal("$pid/$lname: transition from 'unapproved' ".
"requires allocation of resources, use -R");
}
if ($state eq "unapproved") {
fatal("$pid/$lname: cannot return lease to unapproved state.");
}
if ($state eq "initializing" || $lease->UpdateState($state)) {
if ($state eq LEASE_STATE_UNAPPROVED()) {
if ($doresources) {
if ($lease->DeallocResources()) {
fatal("$pid/$lname: could not deallocate resources ".
"when moving to unapproved.");
}
} else {
fatal("$pid/$lname: transition to 'unapproved' ".
"requires deallocation of resources, use -R");
}
}
}
# We do this if ostate == nstate so that you can update the statestamp
if ($lease->UpdateState($state)) {
fatal("$pid/$lname: could not set state to '$state'.");
}
if ($state eq $curstate) {
print "$pid/$lname: set state timestamp.\n";
} else {
print "$pid/$lname: changed state from '$curstate' to '$state'.\n";
}
}
# Handle expiration date
if ($expire && $lease->SetEndTime($expire)) {
if ($expire) {
# XXX in case time ticked on us after we got "now"
$expire = time()
if ($expire == $now);
if ($lease->SetEndTime($expire)) {
fatal("$pid/$lname: could not update expiration time.");
} else {
my $t = localtime($expire);
print "$pid/$lname: set expiration date to '$t'.\n";
}
}
# Handle last used date
......@@ -228,19 +354,30 @@ if (defined($lastused)) {
if (($lastused >= $now && $lease->BumpLastUsed()) ||
($lastused < $now && $lease->SetLastUsedTime($lastused))) {
fatal("$pid/$lname: could not update last-used time.");
} elsif ($lastused == 0) {
print "$pid/$lname: set last_used date to never.\n";
} else {
my $t = localtime($lastused);
print "$pid/$lname: set last_used date to '$t'.\n";
}
}
#
# Handle attributes. Delete, then add (replace).
# Handle attributes. Delete, then add (or replace).
#
if ($delattr && $lease->DeleteAttribute($delattr)) {
if ($delattr) {
if ($lease->DeleteAttribute($delattr)) {
fatal("$pid/$lname: could not remove attribute '$delattr'.");
} else {
print "$pid/$lname: deleted attribute '$delattr'.\n";
}
}
if ($addattr) {
if ($addattr !~ /^([-\w]+)=([-\w\.\+\/:]+)$/ ||
$lease->SetAttribute($1, $2)) {
fatal("$pid/$lname: could not set attribute '$addattr'.");
} else {
print "$pid/$lname: added attribute '$addattr'.\n";
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment