Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
emulab
emulab-devel
Commits
92c00072
Commit
92c00072
authored
Dec 15, 2014
by
Leigh B Stoller
Browse files
Lots more dataset changes. Modify and extend works, and I cleaned
up the embedding so that its less confusing.
parent
76bf66ac
Changes
12
Hide whitespace changes
Inline
Side-by-side
apt/APT_Dataset.pm.in
View file @
92c00072
...
...
@@ -476,6 +476,73 @@ sub DeleteDataset($)
return
Genixmlrpc
::
CallMethod
($
cmurl
,
$
context
,
"DeleteDataset"
,
$
args
);
}
#
#
Apply
some
updates
to
the
dataset
on
server
.
#
sub
ModifyDataset
($)
{
my
($
self
)
=
@
_
;
my
$
authority
=
$
self
->
GetGeniAuthority
();
my
$
geniuser
=
$
self
->
GetGeniUser
();
my
$
context
=
APT_Geni
::
GeniContext
();
my
$
cert
=
$
self
->
GetCertificate
();
return
undef
if
(
! (defined($geniuser) && defined($authority) &&
defined
($
context
)
&&
defined
($
cert
)));
my
($
credential
,
$
speaksfor_credential
)
=
APT_Geni
::
GenCredentials
($
cert
,
$
geniuser
,
[
"blockstores"
]);
return
undef
if
(
! (defined($speaksfor_credential) &&
defined
($
credential
)));
my
$
args
=
{
"name"
=>
$
self
->
dataset_id
(),
"credentials"
=>
[$
credential
->
asString
(),
$
speaksfor_credential
->
asString
()],
};
#
This
is
all
we
can
change
right
now
.
$
args
->{
"expires"
}
=
emutil
::
TBDateStringGMT
($
self
->
expires
())
if
(
defined
($
self
->
expires
()));
my
$
cmurl
=
$
authority
->
url
();
$
cmurl
=~
s
/
protogeni
/
protogeni
\/
stoller
/;
return
Genixmlrpc
::
CallMethod
($
cmurl
,
$
context
,
"ModifyDataset"
,
$
args
);
}
#
#
Request
single
extension
.
#
sub
ExtendDataset
($)
{
my
($
self
)
=
@
_
;
my
$
authority
=
$
self
->
GetGeniAuthority
();
my
$
geniuser
=
$
self
->
GetGeniUser
();
my
$
context
=
APT_Geni
::
GeniContext
();
my
$
cert
=
$
self
->
GetCertificate
();
return
undef
if
(
! (defined($geniuser) && defined($authority) &&
defined
($
context
)
&&
defined
($
cert
)));
my
($
credential
,
$
speaksfor_credential
)
=
APT_Geni
::
GenCredentials
($
cert
,
$
geniuser
,
[
"blockstores"
]);
return
undef
if
(
! (defined($speaksfor_credential) &&
defined
($
credential
)));
my
$
args
=
{
"name"
=>
$
self
->
dataset_id
(),
"credentials"
=>
[$
credential
->
asString
(),
$
speaksfor_credential
->
asString
()],
"extend"
=>
1
,
};
my
$
cmurl
=
$
authority
->
url
();
$
cmurl
=~
s
/
protogeni
/
protogeni
\/
stoller
/;
return
Genixmlrpc
::
CallMethod
($
cmurl
,
$
context
,
"ModifyDataset"
,
$
args
);
}
#
#
Refresh
our
metadata
.
#
...
...
apt/manage_dataset.in
View file @
92c00072
...
...
@@ -37,6 +37,8 @@ sub usage()
print
STDERR
"
Usage: manage_dataset [options --] create ...
\n
";
print
STDERR
"
Usage: manage_dataset [options --] delete ...
\n
";
print
STDERR
"
Usage: manage_dataset [options --] refresh ...
\n
";
print
STDERR
"
Usage: manage_dataset [options --] modify ...
\n
";
print
STDERR
"
Usage: manage_dataset [options --] extend ...
\n
";
exit
(
-
1
);
}
my
$optlist
=
"
dt:
";
...
...
@@ -82,6 +84,8 @@ sub DoCreate();
sub
DoDelete
();
sub
DoRefresh
();
sub
DoRefreshInternal
($$);
sub
DoModify
();
sub
DoExtend
();
#
# Parse command arguments. Once we return from getopts, all that should be
...
...
@@ -133,6 +137,12 @@ elsif ($action eq "delete") {
elsif
(
$action
eq
"
refresh
")
{
exit
(
DoRefresh
());
}
elsif
(
$action
eq
"
modify
")
{
exit
(
DoModify
());
}
elsif
(
$action
eq
"
extend
")
{
exit
(
DoExtend
());
}
else
{
usage
();
}
...
...
@@ -400,7 +410,7 @@ sub DoRefreshInternal($$)
my
$response
=
$dataset
->
DescribeDataset
();
if
(
$response
->
code
()
!=
GENIRESPONSE_SUCCESS
)
{
if
(
$response
->
code
()
!
=
GENIRESPONSE_SEARCHFAILED
)
{
if
(
$response
->
code
()
=
=
GENIRESPONSE_SEARCHFAILED
)
{
$$pmesg
=
"
Dataset no longer exists at the target
\n
";
}
else
{
...
...
@@ -421,6 +431,131 @@ sub DoRefreshInternal($$)
return
0
;
}
#
# Modify
#
sub
DoModify
()
{
my
$errmsg
;
my
$usage
=
sub
{
print
STDERR
"
Usage: manage_dataset modify
"
.
"
[-e expiration] [-p privacy] pid/name
\n
";
exit
(
-
1
);
};
my
$optlist
=
"
e:p:
";
my
%options
=
();
if
(
!
getopts
(
$optlist
,
\
%options
))
{
&$usage
();
}
if
(
@ARGV
!=
1
)
{
&$usage
();
}
my
$token
=
shift
(
@ARGV
);
my
$dataset
=
APT_Dataset
->
Lookup
(
$token
);
if
(
!
defined
(
$dataset
))
{
fatal
("
No such dataset
");
}
if
(
defined
(
$options
{"
p
"}))
{
&$usage
()
if
(
$options
{"
p
"}
!~
/^(private|shared|public)$/
);
}
if
(
defined
(
$options
{"
e
"}))
{
my
$expires
=
str2time
(
$options
{"
e
"});
if
(
!
defined
(
$expires
))
{
fatal
("
Could not parse expiration date.
");
}
}
if
(
$dataset
->
Lock
())
{
fatal
("
dataset is busy, cannot lock it
");
}
if
(
defined
(
$options
{"
p
"}))
{
my
$privacy
=
$options
{"
p
"};
my
$blob
=
{"
shared
"
=>
0
,
"
public
"
=>
0
};
if
(
$privacy
eq
"
shared
")
{
$blob
->
{'
shared
'}
=
1
;
}
elsif
(
$privacy
eq
"
public
")
{
$blob
->
{'
public
'}
=
1
;
}
if
(
$dataset
->
Update
(
$privacy
))
{
$errmsg
=
"
Could not update privacy settings!
";
goto
failed
;
}
}
if
(
defined
(
$options
{"
e
"}))
{
my
$expires
=
$options
{"
e
"};
print
"
$expires
\n
";
if
(
$dataset
->
Update
({"
expires
"
=>
TBDateStringLocal
(
$expires
)}))
{
$errmsg
=
"
Could not update expiration!
";
goto
failed
;
}
}
my
$response
=
$dataset
->
ModifyDataset
();
if
(
$response
->
code
()
!=
GENIRESPONSE_SUCCESS
)
{
if
(
$response
->
code
()
==
GENIRESPONSE_SEARCHFAILED
)
{
$errmsg
=
"
Dataset no longer exists at the target
\n
";
}
else
{
$errmsg
=
"
ModifyDataset failed:
"
.
$response
->
output
()
.
"
\n
";
}
goto
failed
;
}
my
$blob
=
$response
->
value
();
$dataset
->
Update
({"
expires
"
=>
TBDateStringLocal
(
$blob
->
{"
expires
"})});
$dataset
->
Unlock
();
return
0
;
failed:
$dataset
->
Unlock
();
# This will set the webtask, see below.
fatal
(
$errmsg
);
}
#
# Extend
#
sub
DoExtend
()
{
my
$errmsg
;
my
$usage
=
sub
{
print
STDERR
"
Usage: manage_dataset extend pid/name
\n
";
exit
(
-
1
);
};
if
(
@ARGV
!=
1
)
{
&$usage
();
}
my
$token
=
shift
(
@ARGV
);
my
$dataset
=
APT_Dataset
->
Lookup
(
$token
);
if
(
!
defined
(
$dataset
))
{
fatal
("
No such dataset
");
}
if
(
$dataset
->
Lock
())
{
fatal
("
dataset is busy, cannot lock it
");
}
my
$response
=
$dataset
->
ExtendDataset
();
if
(
$response
->
code
()
!=
GENIRESPONSE_SUCCESS
)
{
if
(
$response
->
code
()
==
GENIRESPONSE_SEARCHFAILED
)
{
$errmsg
=
"
Dataset no longer exists at the target
\n
";
}
else
{
$errmsg
=
"
ExtendDataset failed:
"
.
$response
->
output
()
.
"
\n
";
}
goto
failed
;
}
my
$blob
=
$response
->
value
();
$dataset
->
Update
({"
expires
"
=>
TBDateStringLocal
(
$blob
->
{"
expires
"})});
$dataset
->
Unlock
();
return
0
;
failed:
$dataset
->
Unlock
();
# This will set the webtask, see below.
fatal
(
$errmsg
);
}
sub
fatal
($)
{
my
(
$mesg
)
=
@_
;
...
...
protogeni/lib/GeniCMV2.pm.in
View file @
92c00072
...
...
@@ -3203,6 +3203,8 @@ sub ConsoleURL($)
#
my
$
CREATEDATASET
=
"$TB/bin/createdataset"
;
my
$
DELETEDATASET
=
"$TB/bin/deletelease"
;
my
$
MODIFYDATASET
=
"$TB/bin/modlease"
;
my
$
EXTENDDATASET
=
"$TB/bin/extendlease"
;
sub
CreateDataset
($)
{
...
...
@@ -3361,12 +3363,85 @@ sub DeleteDataset($)
}
return
GeniResponse
->
Create
(
GENIRESPONSE_SUCCESS
);
}
sub
Extend
Dataset
($)
sub
Modify
Dataset
($)
{
my
($
argref
)
=
@
_
;
my
$
credentials
=
$
argref
->{
'credentials'
};
my
$
dataset
=
$
argref
->{
'name'
};
require
Lease
;
if
(
! (defined($credentials) && defined($dataset))) {
return
GeniResponse
->
MalformedArgsResponse
(
"Missing arguments"
);
}
if
($
dataset
!~ /^[-\w]+$/) {
return
GeniResponse
->
MalformedArgsResponse
(
"Bad dataset name"
);
}
my
($
credential
,$
speaksfor
)
=
GeniStd
::
CheckCredentials
($
credentials
);
return
$
credential
if
(
GeniResponse
::
IsResponse
($
credential
));
#
#
Only
real
local
users
can
do
blockstores
,
or
the
credential
#
must
include
the
correct
priv
.
#
my
$
user
=
GeniUser
->
Lookup
($
credential
->
owner_cert
()->
urn
(),
1
);
return
GeniResponse
->
Create
(
GENIRESPONSE_FORBIDDEN
)
if
(
! ((defined($user) && $user->IsLocal()) ||
$
credential
->
HasActualPrivilege
(
"blockstores"
)));
#
Get
the
project
and
group
.
This
needs
more
thought
.
my
$
group
=
GeniUtil
::
GetHoldingProject
($
credential
->
target_urn
(),
$
user
);
return
$
group
if
(
GeniResponse
::
IsResponse
($
group
));
return
GeniResponse
->
Create
(
GENIRESPONSE_NOT_IMPLEMENTED
);
my
$
lease
=
Lease
->
Lookup
($
group
->
pid
(),
$
group
->
gid
(),
$
dataset
);
if
(
!defined($lease)) {
return
GeniResponse
->
Create
(
GENIRESPONSE_SEARCHFAILED
);
}
#
#
Only
the
creator
can
modify
the
dataset
.
#
return
GeniResponse
->
Create
(
GENIRESPONSE_FORBIDDEN
)
if
(
0
&&
$
user
->
uid
()
ne
$
lease
->
owner
());
my
$
cmd
;
#
#
All
we
can
handle
is
the
expiration
date
.
#
if
(
exists
($
argref
->{
'expires'
}))
{
my
$
expiration
=
$
argref
->{
'expires'
};
#
Gack
,
why
does
Frontier
do
this
.
It
is
stupid
.
if
(
ref
($
expiration
)
eq
'Frontier::RPC2::DateTime::ISO8601'
)
{
$
expiration
=
$
expiration
->
value
;
}
if
(
!str2time($expiration)) {
return
GeniResponse
->
MalformedArgsResponse
(
"Bad expiration"
);
}
GeniUtil
::
FlipToElabMan
();
$
cmd
=
"$WAP $MODIFYDATASET "
;
$
cmd
.=
" -e '"
.
emutil
::
TBDateStringLocal
($
expiration
)
.
"' "
;
}
elsif
(
exists
($
argref
->{
'extend'
}))
{
$
cmd
=
"$EXTENDDATASET "
;
}
else
{
return
GeniResponse
->
Create
(
GENIRESPONSE_SUCCESS
);
}
$
cmd
.=
" "
.
$
group
->
pid
()
.
"/"
.
$
group
->
gid
()
.
"/"
.
$
dataset
;
my
$
output
=
GeniUtil
::
ExecQuiet
($
cmd
);
#
Not
a
typical
op
,
so
always
print
debugging
info
;
print
STDERR
$
output
;
if
($?)
{
return
GeniResponse
->
Create
(
GENIRESPONSE_ERROR
,
undef
,
$
output
);
}
$
lease
->
Refresh
();
my
$
blob
=
{};
$
blob
->{
'expires'
}
=
emutil
::
TBDateStringGMT
($
lease
->
lease_end
());
return
GeniResponse
->
Create
(
GENIRESPONSE_SUCCESS
,
$
blob
);
}
sub
DescribeDataset
($)
{
...
...
www/aptui/create-dataset.php
View file @
92c00072
...
...
@@ -94,6 +94,7 @@ function SPITFORM($formfields, $errors)
echo
"<script type='text/javascript'>
\n
"
;
echo
" window.AJAXURL = 'server-ajax.php';
\n
"
;
echo
" window.TITLE = '
$title
';
\n
"
;
echo
" window.EDITING = false;
\n
"
;
echo
" window.BUTTONLABEL = '
$button_label
';
\n
"
;
echo
"</script>
\n
"
;
...
...
@@ -116,6 +117,10 @@ if (! isset($create)) {
$defaults
[
"dataset_type"
]
=
'stdataset'
;
$defaults
[
"dataset_fstype"
]
=
'ext3'
;
$defaults
[
"dataset_who"
]
=
'shared'
;
# Default project.
if
(
count
(
$projlist
)
==
1
)
{
$defaults
[
"dataset_pid"
]
=
$projlist
[
0
];
}
SPITFORM
(
$defaults
,
$errors
);
return
;
...
...
www/aptui/dataset.ajax
View file @
92c00072
...
...
@@ -41,6 +41,7 @@ function Do_CreateDataSet()
$this_uid
=
$this_user
->
uid
();
# Allow for form precheck only. So JS code knows it will be fast.
$checkonly
=
isset
(
$ajax_args
[
"checkonly"
])
&&
$ajax_args
[
"checkonly"
];
$embedded
=
isset
(
$ajax_args
[
"embedded"
])
&&
$ajax_args
[
"embedded"
];
if
(
!
isset
(
$ajax_args
[
"formfields"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing formfields"
);
...
...
@@ -55,7 +56,10 @@ function Do_CreateDataSet()
$command
=
"webmanage_dataset create "
;
}
$required
=
array
(
"dataset_pid"
,
"dataset_name"
,
"dataset_type"
,
"dataset_size"
,
"dataset_fstype"
,
"dataset_who"
);
"dataset_size"
,
"dataset_fstype"
);
if
(
!
$embedded
)
{
$required
[]
=
"dataset_who"
;
}
foreach
(
$required
as
$field
)
{
if
(
!
isset
(
$formfields
[
$field
])
||
$formfields
[
$field
]
==
""
)
{
...
...
@@ -118,13 +122,15 @@ function Do_CreateDataSet()
$command
.
=
" -s "
.
$formfields
[
"dataset_size"
];
}
# Permission bits.
if
(
$formfields
[
"dataset_who"
]
!=
"public"
&&
$formfields
[
"dataset_who"
]
!=
"shared"
&&
$formfields
[
"dataset_who"
]
!=
"private"
)
{
$errors
[
"dataset_who"
]
=
"Illegal value"
;
}
else
{
$command
.
=
" -p "
.
$formfields
[
"dataset_who"
];
if
(
!
$embedded
)
{
if
(
$formfields
[
"dataset_who"
]
!=
"public"
&&
$formfields
[
"dataset_who"
]
!=
"shared"
&&
$formfields
[
"dataset_who"
]
!=
"private"
)
{
$errors
[
"dataset_who"
]
=
"Illegal value"
;
}
else
{
$command
.
=
" -p "
.
$formfields
[
"dataset_who"
];
}
}
if
(
count
(
$errors
))
{
SPITAJAX_ERROR
(
2
,
$errors
);
...
...
@@ -153,7 +159,103 @@ function Do_CreateDataSet()
return
1
;
}
$dataset_uuid
=
$dataset
->
uuid
();
SPITAJAX_RESPONSE
(
"
$APTBASE
/show-dataset.php?uuid=
$dataset_uuid
"
);
SPITAJAX_RESPONSE
(
"show-dataset.php?uuid=
$dataset_uuid
"
);
}
#
# Server side of modifying a dataset.
#
function
Do_ModifyDataSet
()
{
global
$this_user
;
global
$ajax_args
;
global
$DBFieldErrstr
,
$TBDIR
,
$APTBASE
,
$embedded
;
global
$suexec_output
,
$suexec_output_array
;
$islease
=
1
;
$this_idx
=
$this_user
->
uid_idx
();
$this_uid
=
$this_user
->
uid
();
# Allow for form precheck only. So JS code knows it will be fast.
$checkonly
=
isset
(
$ajax_args
[
"checkonly"
])
&&
$ajax_args
[
"checkonly"
];
$embedded
=
isset
(
$ajax_args
[
"embedded"
])
&&
$ajax_args
[
"embedded"
];
if
(
!
isset
(
$ajax_args
[
"formfields"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing formfields"
);
return
;
}
$formfields
=
$ajax_args
[
"formfields"
];
$errors
=
array
();
if
(
!
isset
(
$formfields
[
"dataset_uuid"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing dataset uuid"
);
return
1
;
}
$dataset_uuid
=
$formfields
[
"dataset_uuid"
];
#
# Either a local lease or a remote dataset.
#
$dataset
=
Lease
::
Lookup
(
$dataset_uuid
);
if
(
!
$dataset
)
{
$dataset
=
Dataset
::
Lookup
(
$dataset_uuid
);
$islease
=
0
;
}
if
(
!
$dataset
)
{
SPITAJAX_ERROR
(
1
,
"Unknown dataset"
);
return
;
}
if
(
$this_uid
!=
$dataset
->
owner_uid
()
&&
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission"
);
return
;
}
if
(
$islease
)
{
$command
=
"webmodlease "
;
}
else
{
$command
=
"webmanage_dataset modify "
;
}
if
(
$dataset
->
type
()
==
"stdataset"
)
{
if
(
!
isset
(
$formfields
[
"dataset_expires"
])
||
$formfields
[
"dataset_expires"
]
==
""
)
{
$errors
[
"dataset_expires"
]
=
"Missing field"
;
}
elseif
(
!
strtotime
(
$formfields
[
"dataset_expires"
]))
{
$errors
[
"dataset_expires"
]
=
"Illegal value"
;
}
else
{
$command
.
=
" -e "
.
escapeshellarg
(
$formfields
[
"dataset_expires"
]);
}
}
# Permission bits.
if
(
isset
(
$formfields
[
"dataset_who"
]))
{
if
(
$formfields
[
"dataset_who"
]
!=
"public"
&&
$formfields
[
"dataset_who"
]
!=
"shared"
&&
$formfields
[
"dataset_who"
]
!=
"private"
)
{
$errors
[
"dataset_who"
]
=
"Illegal value"
;
}
elseif
(
$dataset
->
PrivacyString
()
!=
$formfields
[
"dataset_who"
])
{
$command
.
=
" -p "
.
$formfields
[
"dataset_who"
];
}
}
if
(
count
(
$errors
))
{
SPITAJAX_ERROR
(
2
,
$errors
);
return
;
}
if
(
$checkonly
)
{
SPITAJAX_RESPONSE
(
0
);
return
;
}
$command
.
=
" "
.
$dataset
->
pid
()
.
"/"
.
$dataset
->
id
();
$retval
=
SUEXEC
(
$this_uid
,
$dataset
->
pid
(),
$command
,
SUEXEC_ACTION_CONTINUE
);
if
(
$retval
)
{
SPITAJAX_ERROR
(
1
,
$suexec_output
);
return
;
}
SPITAJAX_RESPONSE
(
"show-dataset.php?uuid=
$dataset_uuid
"
);
}
function
Do_DeleteDataset
()
...
...
@@ -208,7 +310,7 @@ function Do_DeleteDataset()
SPITAJAX_ERROR
(
1
,
$error
);
return
;
}
SPITAJAX_RESPONSE
(
"
$APTBASE
"
);
SPITAJAX_RESPONSE
(
"
list-datasets.php
"
);
}
function
Do_ApproveDataset
()
...
...
@@ -255,7 +357,7 @@ function Do_ApproveDataset()
SPITAJAX_ERROR
(
1
,
$error
);
return
;
}
SPITAJAX_RESPONSE
(
"
$APTBASE
/
show-dataset.php?uuid=
$
le
ase_uuid
"
);
SPITAJAX_RESPONSE
(
"show-dataset.php?uuid=
$
dat
ase
t
_uuid
"
);
}
function
Do_RefreshDataset
()
...
...
@@ -300,6 +402,62 @@ function Do_RefreshDataset()
SPITAJAX_RESPONSE
(
0
);
}
function
Do_ExtendDataset
()
{
global
$this_user
;
global
$ajax_args
;
global
$suexec_output
,
$suexec_output_array
,
$APTBASE
;
$this_idx
=
$this_user
->
uid_idx
();
$this_uid
=
$this_user
->
uid
();
$islease
=
1
;
if
(
!
isset
(
$ajax_args
[
"uuid"
]))
{
SPITAJAX_ERROR
(
1
,
"Missing uuid"
);
return
;
}
#
# Either a local lease or a remote dataset.
#
$dataset
=
Lease
::
Lookup
(
$ajax_args
[
"uuid"
]);
if
(
!
$dataset
)
{
$dataset
=
Dataset
::
Lookup
(
$ajax_args
[
"uuid"
]);
$islease
=
0
;
}
if
(
!
$dataset
)
{
SPITAJAX_ERROR
(
1
,
"Unknown dataset"
);
return
;
}
if
(
$this_uid
!=
$dataset
->
owner_uid
()
&&
!
ISADMIN
())
{
SPITAJAX_ERROR
(
1
,
"Not enough permission"
);
return
;
}
if
(
$islease
)
{
$command
=
"webextendlease "
;
}
else
{
$command
=
"webmanage_dataset extend "
;
}
$command
.
=
$dataset
->
pid
()
.
"/"
.
$dataset
->
id
();
#
# Invoke backend.
#
$retval
=
SUEXEC
(
$this_uid
,
$dataset
->
pid
(),
$command
,
SUEXEC_ACTION_CONTINUE
);
if
(
$retval
!=
0
)
{
$error
=
"Transient error; please try again later"
;
if
(
$retval
&&
count
(
$suexec_output_array
))
{
$error
=
$suexec_output_array
;
}
SPITAJAX_ERROR
(
1
,
$error
);
return
;
}
$dataset_uuid
=
$dataset
->
uuid
();
SPITAJAX_RESPONSE
(
"show-dataset.php?uuid=
$dataset_uuid
"
);
}
# Local Variables:
# mode:php
# End:
...
...
www/aptui/edit-dataset.php
0 → 100644
View file @
92c00072
<?php
#
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir
(
".."
);
include
(
"defs.php3"
);
include
(
"lease_defs.php"
);
chdir
(
"apt"
);