Skip to content
Snippets Groups Projects
Commit e661567d authored by Sebastien Ponce's avatar Sebastien Ponce
Browse files

New command lines for dealing with recall groups. One man page is still missing

parent e3e0bb27
No related branches found
No related tags found
No related merge requests found
......@@ -8,6 +8,10 @@
%attr(0755,root,root) usr/bin/enterdiskpool
%attr(0755,root,root) usr/bin/deletediskpool
%attr(0755,root,root) usr/bin/printdiskpool
%attr(0755,root,root) usr/bin/enterrecallgroup
%attr(0755,root,root) usr/bin/modifyrecallgroup
%attr(0755,root,root) usr/bin/deleterecallgroup
%attr(0755,root,root) usr/bin/printrecallgroup
%attr(0755,root,root) usr/bin/entertapepool
%attr(0755,root,root) usr/bin/modifytapepool
%attr(0755,root,root) usr/bin/deletetapepool
......
......@@ -8,6 +8,10 @@ debian/castor/usr/share/man/man1/printsvcclass.1castor.gz
debian/castor/usr/share/man/man1/enterdiskpool.1castor.gz
debian/castor/usr/share/man/man1/deletediskpool.1castor.gz
debian/castor/usr/share/man/man1/printdiskpool.1castor.gz
debian/castor/usr/share/man/man1/enterrecallgroup.1castor.gz
debian/castor/usr/share/man/man1/modifyrecallgroup.1castor.gz
debian/castor/usr/share/man/man1/deleterecallgroup.1castor.gz
debian/castor/usr/share/man/man1/printrecallgroup.1castor.gz
debian/castor/usr/share/man/man1/entertapepool.1castor.gz
debian/castor/usr/share/man/man1/modifytapepool.1castor.gz
debian/castor/usr/share/man/man1/deletetapepool.1castor.gz
......
......@@ -42,6 +42,11 @@ InstallTarget(enterdiskpool,755)
InstallTarget(deletediskpool,755)
InstallTarget(printdiskpool,755)
InstallTarget(enterrecallgroup,755)
InstallTarget(modifyrecallgroup,755)
InstallTarget(deleterecallgroup,755)
InstallTarget(printrecallgroup,755)
InstallTarget(entertapepool,755)
InstallTarget(modifytapepool,755)
InstallTarget(deletetapepool,755)
......@@ -80,6 +85,11 @@ EXEMANPAGE(enterdiskpool)
EXEMANPAGE(deletediskpool)
EXEMANPAGE(printdiskpool)
EXEMANPAGE(enterrecallgroup)
EXEMANPAGE(modifyrecallgroup)
EXEMANPAGE(deleterecallgroup)
EXEMANPAGE(printrecallgroup)
EXEMANPAGE(entertapepool)
EXEMANPAGE(modifytapepool)
EXEMANPAGE(deletetapepool)
......
#!/usr/bin/python
#/******************************************************************************
# * deleterecallgroup
# *
# * This file is part of the Castor project.
# * See http://castor.web.cern.ch/castor
# *
# * Copyright (C) 2003 CERN
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of the GNU General Public License
# * as published by the Free Software Foundation; either version 2
# * of the License, or (at your option) any later version.
# * This program 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 General Public License for more details.
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# *
# * @author Castor Dev team, castor-dev@cern.ch
# *****************************************************************************/
'''command line deleting the recall group(s)'''
import sys
import getopt
import castor_tools
# usage function
def usage(exitCode):
'''prints usage'''
print 'Usage : ' + sys.argv[0] + ' [-h|--help] <recallGroupName>[:...]'
sys.exit(exitCode)
# first parse the options
try:
options, args = getopt.getopt(sys.argv[1:], 'hv', ['help', 'verbose'])
except Exception, e:
print e
usage(1)
verbose = False
for f, v in options:
if f == '-h' or f == '--help':
usage(0)
elif f == '-v' or f == '--verbose':
verbose = True
else:
print "unknown option : " + f
usage(1)
# Deal with arguments
recallGroups = set([])
if len(args) != 0:
recallGroups = set(args[0].split(':'))
else:
print "Missing arguments"
usage(1)
try:
# connect to stager
stconn = castor_tools.connectToStager()
stcur = stconn.cursor()
# check tape pool existence
stcur.execute("SELECT name FROM RecallGroup WHERE name IN ('" + "', '".join(recallGroups) + "')")
existingRecallGroups = set([row[0] for row in stcur.fetchall()])
nonexitingRecallGroups = recallGroups - existingRecallGroups
# forbid deletion of the default group
if 'default' in existingRecallGroups:
print 'Recall group default should be deleted. Giving up'
sys.exit(1)
# check that the recall groups are not containing any user
stcur.execute('''SELECT RecallGroup.name, count(*)
FROM RecallUser, RecallGroup
WHERE RecallUser.recallGroup = RecallGroup.id
AND RecallGroup.name IN (\'''' + "', '".join(existingRecallGroups) + "') " + '''
GROUP BY RecallGroup.name''')
rows = stcur.fetchall()
if len(rows) > 0:
print 'RecallGroups cannot be dropped when they still contain users :'
for rg, nb in rows:
print ' - recall group %s contains %d user(s)' % (rg, nb)
print 'You may want to use deleterecalluser or modifyrecalluser to correct this'
sys.exit(1)
# check that the tape pools are not used by any ongoing RecallJob
stcur.execute('''SELECT RecallGroup.name, count(*)
FROM RecallJob, RecallGroup
WHERE RecallJob.recallGroup = RecallGroup.id
AND RecallGroup.name IN (\'''' + "', '".join(existingRecallGroups) + '''\')
GROUP BY RecallGroup.name''')
rows = stcur.fetchall()
if len(rows) > 0:
print 'RecallGroups cannot be dropped when used by some recall jobs :'
for tp, nb in rows:
print ' - recall group %s is in use by %d recall jobs' % (tp, nb)
print 'You probably have to wait that the recall of these files is over'
sys.exit(1)
# check that the tape pools are not used by any ongoing RecallMount
stcur.execute('''SELECT RecallGroup.name, count(*)
FROM RecallMount, RecallGroup
WHERE RecallMount.recallGroup = RecallGroup.id
AND RecallGroup.name IN (\'''' + "', '".join(existingRecallGroups) + '''\')
GROUP BY RecallGroup.name''')
rows = stcur.fetchall()
if len(rows) > 0:
print 'RecallGroups cannot be dropped when used by some recall mount :'
for tp, nb in rows:
print ' - recall group %s is in use by %d recall mounts' % (tp, nb)
print 'You probably have to wait that the mount is over. Note that there was no RecallJob left so it should be a matter of seconds'
sys.exit(1)
# drop recall group
if existingRecallGroups:
stcur.execute("DELETE FROM RecallGroup WHERE name IN ('" + "', '".join(existingRecallGroups) + "')")
stconn.commit()
print 'successfully dropped the following recall groups : ' + ', '.join(existingRecallGroups)
# warn for non existing tape pools
if nonexitingRecallGroups:
print 'WARNING : some recall group(s) did not exist : ' + ', '.join(nonexitingRecallGroups)
# close DB connections
try:
castor_tools.disconnectDB(stconn)
except Exception:
pass
except Exception, e:
print e
if verbose:
import traceback
traceback.print_exc()
sys.exit(-1)
.TH DELETERECALLGROUP 1 "2011" CASTOR "stager catalogue administrative commands"
.SH NAME
deleterecallgroup \- deletes existing recall groups from the stager catalogue
.SH SYNOPSIS
.B deleterecallgroup
[
.BI -h
]
.BI <recallGroupName>
[:...]
.SH DESCRIPTION
.B deleterecallgroup
deletes existing recall groups from the CASTOR stager catalog
.LP
.BI \-h,\ \-\-help
Get usage information
.TP
.BI <recallGroupName>
name of recall groups to delete. Several names can be given, colon separated
.SH EXAMPLES
.nf
.ft CW
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
-----------------------------------------------------------------------------------------------------------------------
newrecallgroup 0 100GiB 1000 12h 0 263333 root 30-May-2012 17:29:12
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
testrecallgroup 2 23MiB 1000 12h23mn 456 263419 root 30-May-2012 17:31:11
# deleterecallgroup newrecallgroup
successfully dropped the following recall groups : newrecallgroup
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
---------------------------------------------------------------------------------------------------------------------------
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
testrecallgroup 2 23MiB 1000 12h23mn 456 263419 root 30-May-2012 17:31:11
# deleterecallgroup newrecallgroup:testrecallgroup
successfully dropped the following recall groups : testrecallgroup
WARNING : some recall group(s) did not exist : newrecallgroup
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
-------------------------------------------------------------------------------------------------------------------
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
# deleterecallgroup default
Recall group default should be deleted. Giving up
In case a user still belongs to a recall group, you may get this :
# deleterecallgroup testrecallgroup
RecallGroups cannot be dropped when they still contain users :
- recall group testrecallgroup contains 1 users
You may want to use deleterecalluser or modifyrecalluser to correct this
.SH NOTES
This command requires database client access to the stager catalogue.
Configuration for the database access is taken from castor.conf.
.SH SEE ALSO
.BR enterrecallgroup,
.BR modifyrecallgroup,
.BR printrecallgroup,
.BR deletediskpool,
.BR deletesvcclass,
.BR deletetapepool,
.BR deletefileclass,
.BR deletemigrationroute,
.BR adminMultiInstance
.SH AUTHOR
\fBCASTOR\fP Team <castor.support@cern.ch>
#!/usr/bin/python
#/******************************************************************************
# * enterrecallgroup
# *
# * This file is part of the Castor project.
# * See http://castor.web.cern.ch/castor
# *
# * Copyright (C) 2003 CERN
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of the GNU General Public License
# * as published by the Free Software Foundation; either version 2
# * of the License, or (at your option) any later version.
# * This program 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 General Public License for more details.
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# *
# * @author castor dev team
# *****************************************************************************/
'''allows to enter a new recall group into the castor stager'''
import sys, re, os, pwd
import getopt
import castor_tools
# usage function
def usage(exitCode):
'''prints usage'''
print 'Usage : ' + sys.argv[0] + ' [-h|--help] [--nbdrives <nbDrives>] ' + \
'[--minamountdata <minAmountDataForAMount>] [--minnbfiles <minNbFilesForAMount>] ' + \
'[--maxfileage <maxFileAgeBeforeForcedMount>] [--priority <VDQMPriority>] <recallGroupName>'
sys.exit(exitCode)
def parsePositiveInt(name, svalue):
'''parses a positive int value and exits with proper error message in case the value does not fit'''
try:
value = int(svalue)
if value < 0:
raise ValueError
return value
except ValueError:
print 'Invalid %s %s' % (name, svalue)
usage(1)
def parseDataAmount(name, svalue):
'''parses a value describing an amount of data. Exits with proper error message in case the value does not fit'''
try:
exts = {'K' : 1000, 'M' : 1000*1000, 'G' : 1000*1000*1000, 'T' : 1000*1000*1000*1000,
'Ki' : 1024, 'Mi' : 1024*1024, 'Gi' : 1024*1024*1024, 'Ti' : 1024*1024*1024*1024}
regexp = re.compile('^(?P<nb>\d+)(?P<ext>(?:[KMGT]i?)?)B?$')
m = regexp.match(svalue)
if not m:
raise ValueError
value = int(m.group('nb'))
if m.group('ext'):
value *= exts[m.group('ext')]
return value
except ValueError:
print 'Invalid %s %s' % (name, svalue)
usage(1)
def parseTimeDuration(name, svalue):
'''parses a value describing a time duration. Exits with proper error message in case the value does not fit'''
try:
# check validity
if not re.compile('^(\d+(s|mn?|h|d)?)+$').match(svalue):
raise ValueError
# parse
exts = {'s' : 1, 'm' : 60, 'mn' : 60, 'h' : 3600, 'd' : 86400}
regexp = re.compile('(\d+)(s|mn?|h|d)?')
value = 0
for nb, ext in regexp.findall(svalue):
partvalue = int(nb)
if ext:
partvalue *= exts[ext]
value += partvalue
return value
except ValueError:
print 'Invalid %s %s' % (name, svalue)
usage(1)
# first parse the options
try:
options, args = getopt.getopt(sys.argv[1:], 'hv', ['help', 'verbose', 'nbdrives=', 'minamountdata=',
'minnbfiles=', 'maxfileage=', 'priority='])
except Exception, e:
print e
usage(1)
verbose = False
nbdrives = 0
minamountdata = 100*1024*1024*1024 # 100GiB
minnbfiles = 1000
maxfileage = 43200 # 12h
priority = 0
for f, v in options:
if f == '-h' or f == '--help':
usage(0)
elif f == '-v' or f == '--verbose':
verbose = True
elif f == '--nbdrives':
nbdrives = parsePositiveInt('nbdrives', v)
elif f == '--minamountdata':
minamountdata = parseDataAmount('minamountdata', v)
elif f == '--minnbfiles':
minnbfiles = parsePositiveInt('minnbfiles', v)
elif f == '--maxfileage':
maxfileage = parseTimeDuration('maxfileage', v)
elif f == '--priority':
priority = parsePositiveInt('priority', v)
else:
print "unknown option : " + f
usage(1)
# Deal with arguments
if len(args) == 0:
print "Missing arguments"
usage(1)
elif len(args) > 1:
print "Too many arguments"
usage(1)
recallGroupName = args[0]
try:
# connect to stager
stconn = castor_tools.connectToStager()
stcur = stconn.cursor()
# check whether the recall group already exists
stcur.execute('SELECT id FROM RecallGroup WHERE name=:name', name=recallGroupName)
rows = stcur.fetchall()
if len(rows) != 0:
print 'RecallGroup %s already exists in the stager DB' % recallGroupName
print 'You may want to use modifyrecallgroup'
sys.exit(1)
# get info on user running this command
lasteditor = pwd.getpwuid(os.getuid())[0]
# insert new recallGroup
stcur.execute('''INSERT INTO RecallGroup
(name, nbDrives, minAmountDataForMount, minNbFilesForMount, maxFileAgeBeforeMount,
VDQMPriority, lastEditor, lastEditionTime, id)
VALUES
(:name, :nbdrives, :minamountdata, :minnbfiles, :maxfileage,
:priority, :lasteditor, gettime(), ids_seq.nextval)''',
name=recallGroupName, nbdrives=nbdrives, minamountdata=minamountdata,
minnbfiles=minnbfiles, maxfileage=maxfileage, priority=priority, lasteditor=lasteditor)
stconn.commit()
print 'inserted recall group %s successfully' % recallGroupName
# close DB connection
try:
castor_tools.disconnectDB(stconn)
except Exception:
pass
except Exception, e:
print e
if verbose:
import traceback
traceback.print_exc()
sys.exit(-1)
.TH ENTERRECALLGROUP 1 "2011" CASTOR "stager catalog administrative commands"
.SH NAME
enterrecallgroup \- enter a new tape pool in the stager catalog
.SH SYNOPSIS
.B enterrecallgroup
[
.BI -h
]
[
.BI --nbdrives
<nbDrives>
]
[
.BI --minamountdata
.B <minAmountDataForAMount>
]
[
.BI --minnbfiles
.B <minNbFilesForAMount>
]
[
.BI --maxfileage
.B <maxFileAgeBeforeForcedMount>
]
[
.BI --priority
.B <VDQMPriority>
]
.BI <recallGroupName>
.SH DESCRIPTION
.B enterrecallgroup
enters a new recall group in the CASTOR stager catalog.
The parameters of the recall group define the policy used to trigger tape mounts in case users of this group want to recall some files.
The behavior is the following :
- never more than <nbDrives> drives can be used concurrently
- a new tape will be mounted whenever we have either more than <minAmountDataForAMount> of data or <minNbFilesForAMount> files waiting for recall. In practice, if some migrations are already running, a new one is trigerred if one of these 2 numbers will still be exceeded per mount, even with the new mount.
- a tape mount will be forced if nothing is mounted and one file becomes older than maxFileAgeBeforeForcedMount
- if a tape mount is triggered, VDQM will be called to get a drive with the given priority
.TP
.BI \-h,\ \-\-help
Get usage information
.TP
.BI \-\-nbdrives <nbDrives>
The maximum number of tape drives this tape pool is allowed to use concurrently
for migration. Default is 0 is not provided
.TP
.BI \-\-minamountdata <minAmountDataForAMount>
The minimum amount of data needed to trigger a new mount in bytes. Default is 100GiB if not provided.
The value can be given using the standard K/M/G/T extensions, with or without B (i.e. both KB and K are accepted).
These have the ISO meaning of powers of 10. Ki/Mi/Gi/Ti[B] extensions are also accepted and deal with powers of 2.
.TP
.BI \-\-minnbfiles <minNbFilesForAMount>
The minimum number of files needed to trigger a new mount. Default is 1000 if not provided.
.TP
.BI \-\-maxfileage <maxFileAgeBeforeForcedMount>
The maximum age of a file before a new mount is triggered. Default is 12h if not provided.
The value can be given using the extensions s/m/mn/h/d for seconds, minutes(both m and mn), hours and days.
.TP
.BI \-\-priority <VDQMpriority>
The priority to be used when accessing VDQM to get a drive. Default is 0 if not provided.
.TP
.BI <recallGroupName>
name of a tape pool to create.
.SH EXAMPLES
.nf
.ft CW
# enterrecallgroup newrecallgroup
inserted recall group newrecallgroup successfully
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
----------------------------------------------------------------------------------------------------------------------
newrecallgroup 0 100GiB 1000 12h 0 263333 root 30-May-2012 17:29:12
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
# enterrecallgroup --nbdrives 2 newrecallgroup
Recallgroup newrecallgroup already exists in the stager DB
You may want to use modifyrecallgroup
# enterrecallgroup --nbdrives 2 --minamountdata 23MiB --maxfileage 12h23mn --priority 456 testrecallgroup
inserted recall group testrecallgroup successfully
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
-----------------------------------------------------------------------------------------------------------------------
newrecallgroup 0 100GiB 1000 12h 0 263333 root 30-May-2012 17:29:12
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
testrecallgroup 2 23MiB 1000 12h23mn 456 263419 root 30-May-2012 17:31:11
.SH NOTES
This command requires database client access to the stager catalog and nameserver DBs.
Configuration for the database accesses is taken from castor.conf.
.SH SEE ALSO
.BR deleterecallgroup,
.BR modifyrecallgroup,
.BR printrecallgroup,
.BR enterdiskpool,
.BR entersvcclass,
.BR enterfileclass,
.BR entertapepool,
.BR entermigrationroute,
.BR adminMultiInstance
.SH AUTHOR
\fBCASTOR\fP Team <castor.support@cern.ch>
#!/usr/bin/python
#/******************************************************************************
# * modifyrecallgroup
# *
# * This file is part of the Castor project.
# * See http://castor.web.cern.ch/castor
# *
# * Copyright (C) 2003 CERN
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of the GNU General Public License
# * as published by the Free Software Foundation; either version 2
# * of the License, or (at your option) any later version.
# * This program 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 General Public License for more details.
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# *
# * @author castor dev team
# *****************************************************************************/
'''allows to modify an existing recall group in the castor stager'''
import sys, re, os, pwd
import getopt
import castor_tools
# usage function
def usage(exitCode):
'''prints usage'''
print 'Usage : ' + sys.argv[0] + ' [-h|--help] [--nbdrives <nbDrives>] ' + \
'[--minamountdata <minAmountDataForAMount>] [--minnbfiles <minNbFilesForAMount>] ' + \
'[--maxfileage <maxFileAgeBeforeForcedMount>] [--priority <VDQMPriority>] <recallGroupName>'
sys.exit(exitCode)
def parsePositiveInt(name, svalue):
'''parses a positive int value and exits with proper error message in case the value does not fit'''
try:
value = int(svalue)
if value < 0:
raise ValueError
return value
except ValueError:
print 'Invalid %s %s' % (name, svalue)
usage(1)
def parseDataAmount(name, svalue):
'''parses a value describing an amount of data. Exits with proper error message in case the value does not fit'''
try:
exts = {'K' : 1000, 'M' : 1000*1000, 'G' : 1000*1000*1000, 'T' : 1000*1000*1000*1000,
'Ki' : 1024, 'Mi' : 1024*1024, 'Gi' : 1024*1024*1024, 'Ti' : 1024*1024*1024*1024}
regexp = re.compile('^(?P<nb>\d+)(?P<ext>(?:[KMGT]i?)?)B?$')
m = regexp.match(svalue)
if not m:
raise ValueError
value = int(m.group('nb'))
if m.group('ext'):
value *= exts[m.group('ext')]
return value
except ValueError:
print 'Invalid %s %s' % (name, svalue)
usage(1)
def parseTimeDuration(name, svalue):
'''parses a value describing a time duration. Exits with proper error message in case the value does not fit'''
try:
# check validity
if not re.compile('^(\d+(s|mn?|h|d)?)+$').match(svalue):
raise ValueError
# parse
exts = {'s' : 1, 'm' : 60, 'mn' : 60, 'h' : 3600, 'd' : 86400}
regexp = re.compile('(\d+)(s|mn?|h|d)?')
value = 0
for nb, ext in regexp.findall(svalue):
partvalue = int(nb)
if ext:
partvalue *= exts[ext]
value += partvalue
return value
except ValueError:
print 'Invalid %s %s' % (name, svalue)
usage(1)
# first parse the options
try:
options, args = getopt.getopt(sys.argv[1:], 'hvm:', ['help', 'verbose', 'nbdrives=', 'minamountdata=',
'minnbfiles=', 'maxfileage=', 'priority='])
except Exception, e:
print e
usage(1)
verbose = False
nbdrives = None
minamountdata = None
minnbfiles = None
maxfileage = None
priority = None
for f, v in options:
if f == '-h' or f == '--help':
usage(0)
elif f == '-v' or f == '--verbose':
verbose = True
elif f == '--nbdrives':
nbdrives = parsePositiveInt('nbdrives', v)
elif f == '--minamountdata':
minamountdata = parseDataAmount('minamountdata', v)
elif f == '--minnbfiles':
minnbfiles = parsePositiveInt('minnbfiles', v)
elif f == '--maxfileage':
maxfileage = parseTimeDuration('maxfileage', v)
elif f == '--priority':
priority = parsePositiveInt('priority', v)
else:
print "unknown option : " + f
usage(1)
# Deal with arguments
if len(args) == 0:
print "Missing arguments"
usage(1)
elif len(args) > 1:
print "Too many arguments"
usage(1)
else:
recallgroupname = args[0]
# check we have something to do
if nbdrives == None and minamountdata == None and minnbfiles == None and maxfileage == None:
print 'Nothing to modify. Did you forget some argument ?'
usage(1)
try:
# connect to stager
stconn = castor_tools.connectToStager()
stcur = stconn.cursor()
# check that the recall group exists
stcur.execute('SELECT id FROM RecallGroup WHERE name=:name', name=recallgroupname)
rows = stcur.fetchall()
if len(rows) == 0:
print 'RecallGroup %s does not exist in the stager DB' % recallgroupname
print 'Please use enterrecallgroup if you would like to create it'
sys.exit(1)
recallGroupId = rows[0][0]
# deal with the update
if nbdrives != None:
stcur.execute('UPDATE RecallGroup SET nbDrives=:value WHERE id = :recallGroupId', value=nbdrives, recallGroupId=recallGroupId)
if minamountdata != None:
stcur.execute('UPDATE RecallGroup SET minAmountdataForMount=:value WHERE id = :recallGroupId', value=minamountdata, recallGroupId=recallGroupId)
if minnbfiles != None:
stcur.execute('UPDATE RecallGroup SET minNbFilesForMount=:value WHERE id = :recallGroupId', value=minnbfiles, recallGroupId=recallGroupId)
if maxfileage != None:
stcur.execute('UPDATE RecallGroup SET maxFileAgeBeforeMount=:value WHERE id = :recallGroupId', value=maxfileage, recallGroupId=recallGroupId)
if priority != None:
stcur.execute('UPDATE RecallGroup SET VDQMPriority=:value WHERE id = :recallGroupId', value=priority, recallGroupId=recallGroupId)
# in all cases, update the lastEditor and lastEditionTime
lasteditor = pwd.getpwuid(os.getuid())[0]
stcur.execute('UPDATE RecallGroup SET lastEditor=:lasteditor, lastEditionTime=gettime() WHERE id = :recallGroupId', lasteditor=lasteditor, recallGroupId=recallGroupId)
# commit insertion and tell user
stconn.commit()
print 'modified recall group %s successfully' % recallgroupname
# close DB connections
try:
castor_tools.disconnectDB(stconn)
except Exception:
pass
except Exception, e:
print e
if verbose:
import traceback
traceback.print_exc()
sys.exit(-1)
.TH MODIFYRECALLGROUP 1 "2011" CASTOR "stager catalogue administrative commands"
.SH NAME
modifyrecallgroup \- modifies an existing recall group in the stager catalog
.SH SYNOPSIS
.B modifyrecallgroup
[
.BI -h
]
[
.BI --nbdrives
<nbDrives>
]
[
.BI --minamountdata
.B <minAmountDataForAMount>
]
[
.BI --minnbfiles
.B <minNbFilesForAMount>
]
[
.BI --maxfileage
.B <maxFileAgeBeforeForcedMount>
]
[
.BI --priority
.B <VDQMpriority>
]
<recallGroupName>
.SH DESCRIPTION
.B modifyrecallgroup
modifies an existing recall group in the CASTOR stager catalog
The parameters of the recallgroup define the policy used to trigger tape mounts for recalls.
The behavior is the following :
- never more than <nbDrives> drives can be used concurrently
- a new tape will be mounted whenever we have either more than <minAmountDataForAMount> of data or <minNbFilesForAMount> files waiting for recall. In practice, if some migrations are already running, a new one is trigerred if one of these 2 numbers will still be exceeded per mount, even with the new mount.
- a tape mount will be forced if nothing is mounted and one file becomes older than maxFileAgeBeforeForcedMount
- if a tape mount is triggered, VDQM will be called to get a drive with the given priority
.TP
.BI \-h,\ \-\-help
Get usage information
.TP
.BI \-\-nbdrives <nbDrives>
The maximum number of tape drives this recall group is allowed to use concurrently
for migration.
.TP
.BI \-\-minamountdata <minAmountDataForAMount>
The minimum amount of data needed to trigger a new mount in bytes.
The value can be given using the standard K/M/G/T extensions, with or without B (i.e. both KB and K are accepted).
These have the ISO meaning of powers of 10. Ki/Mi/Gi/Ti[B] extensions are also accepted and deal with powers of 2.
.TP
.BI \-\-minnbfiles <minNbFilesForAMount>
The minimum number of files needed to trigger a new mount.
.TP
.BI \-\-maxfileage <maxFileAgeBeforeForcedMount>
The maximum age of a file before a new mount is triggered.
The value can be given using the extensions s/m/mn/h/d for seconds, minutes(both m and mn), hours and days.
.TP
.BI \-\-priority <VDQMpriority>
The priority to be used when accessing VDQM to get a drive.
.TP
.BI <tapePoolName>
name of the recall group to modify.
.SH EXAMPLES
.nf
.ft CW
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
----------------------------------------------------------------------------------------------------------------------
newrecallgroup 0 100GiB 1000 12h 0 263333 root 30-May-2012 17:29:12
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
# modifyrecallgroup --nbdrives 1 --minamountdata 57MiB --minnbfiles 234 --maxfileage 1d5h --priority 2 newrecallgroup
modified recall group newrecallgroup successfully
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
----------------------------------------------------------------------------------------------------------------------
newrecallgroup 1 57MiB 234 1d5h 2 263333 root 06-Jun-2012 09:35:11
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
.SH NOTES
This command requires database client access to the stager catalog and nameserver DBs.
Configuration for the database accesses is taken from castor.conf.
.SH SEE ALSO
.BR deleterecallgroup,
.BR enterrecallgroup,
.BR printrecallgroup,
.BR modifytapepool
.BR modifysvcclass,
.BR modifymigrationroute,
.BR adminMultiInstance
.SH AUTHOR
\fBCASTOR\fP Team <castor.support@cern.ch>
#!/usr/bin/python
#/******************************************************************************
# * printrecallgroup
# *
# * This file is part of the Castor project.
# * See http://castor.web.cern.ch/castor
# *
# * Copyright (C) 2003 CERN
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of the GNU General Public License
# * as published by the Free Software Foundation; either version 2
# * of the License, or (at your option) any later version.
# * This program 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 General Public License for more details.
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# *
# * @author Castor Dev team, castor-dev@cern.ch
# *****************************************************************************/
'''command line printing the given recall group(s)'''
import sys
import getopt, time
import castor_tools
# usage function
def usage(exitCode):
'''prints usage'''
print 'Usage : ' + sys.argv[0] + ' [-h|--help] [<recallGroupName> [...]]'
sys.exit(exitCode)
def secsToDate(s):
'''converts number of seconds since the epoch into readable date'''
return time.strftime('%d-%b-%Y %H:%M:%S', time.localtime(s))
def nbToDataAmount(n):
'''converts a number into a readable amount of data'''
ext = ['B', 'KiB', 'MiB', 'GiB', 'TiB']
magn = 0
while n / 1024 > 5:
magn += 1
n = n / 1024
return str(n) + ext[magn]
def nbToAge(n):
'''converts a number of seconds into a readable age'''
s = ''
if n >= 86400:
s = s + str(n/86400) + 'd'
n = n % 86400
if n >= 3600:
s = s + str(n/3600) + 'h'
n = n % 3600
if n >= 60:
s = s + str(n/60) + 'mn'
n = n % 60
if n > 0:
s = s + str(n) + 's'
if len(s) == 0:
s = '0s'
return s
# first parse the options
try:
options, args = getopt.getopt(sys.argv[1:], 'hv', ['help', 'verbose'])
except Exception, e:
print e
usage(1)
verbose = False
for f, v in options:
if f == '-h' or f == '--help':
usage(0)
elif f == '-v' or f == '--verbose':
verbose = True
else:
print "unknown option : " + f
usage(1)
# Deal with arguments
recallGroups = None
if len(args) != 0:
recallGroups = set(args)
try:
# connect to stager and prepare statements
stconn = castor_tools.connectToStager()
stcur = stconn.cursor()
sqlStatement = '''
SELECT name, nbDrives, minAmountDataForMount, minNbFilesForMount, maxFileAgeBeforeMount, VDQMPriority,
lastEditor, lastEditionTime, id
FROM RecallGroup'''
if recallGroups:
sqlStatement = sqlStatement + " WHERE name IN ('" + "', '".join(recallGroups) + "')"
stcur.execute(sqlStatement)
# get results
rows = stcur.fetchall()
existingRecallGroups = set([row[0] for row in rows])
if recallGroups:
unknownRecallGroups = recallGroups - existingRecallGroups
# loop over tape pools and print them
if existingRecallGroups:
maxNameLen = max([4] + [len(row[0]) for row in rows])
maxMinAmountDataLen = max([13] + [len(nbToDataAmount(row[2])) for row in rows])
maxMinNbFilesLen = max([10] + [len(str(row[3])) for row in rows])
maxMaxFileAgeLen = max([10] + [len(nbToAge(row[4])) for row in rows])
maxLastEditorLen = max([10] + [len(row[6]) for row in rows if row[6]])
maxLastEditionTimeLen = max([11] + [len(secsToDate(row[7])) for row in rows])
maxIdLen = max([2] + [len(str(row[8])) for row in rows])
print '%*s NBDRIVES %*s %*s %*s VDQMPRIORITY %*s %*s %*s' % \
(maxNameLen, 'NAME', maxMinAmountDataLen, 'MINAMOUNTDATA', maxMinNbFilesLen, \
'MINNBFILES', maxMaxFileAgeLen, 'MAXFILEAGE', maxIdLen, 'ID', \
maxLastEditorLen, 'LASTEDITOR', maxLastEditionTimeLen, 'LASTEDITION')
print '-' * (28 + maxNameLen + maxMinAmountDataLen + maxMinNbFilesLen + maxMaxFileAgeLen + \
maxLastEditorLen + maxLastEditionTimeLen + maxIdLen)
for name, nbdrives, minamountdata, minnbfiles, maxfileage, priority, lastEditor, lastEdition, tpid in rows:
print '%*s %8d %*s %*d %*s %12d %*d %*s %*s' % \
(maxNameLen, name, nbdrives, maxMinAmountDataLen, nbToDataAmount(minamountdata), \
maxMinNbFilesLen, minnbfiles, maxMaxFileAgeLen, nbToAge(maxfileage), priority, maxIdLen, tpid, \
maxLastEditorLen, lastEditor, maxLastEditionTimeLen, secsToDate(lastEdition))
# check unknown tape pools
if recallGroups and unknownRecallGroups:
print 'WARNING : the following recall groups do not exist : ' + ', '.join(unknownRecallGroups)
# close DB connections
try:
castor_tools.disconnectDB(stconn)
except Exception:
pass
except Exception, e:
print e
if verbose:
import traceback
traceback.print_exc()
sys.exit(-1)
.TH PRINTRECALLGROUP 1 "2011" CASTOR "Prints out the given recall group(s)"
.SH NAME
printrecallgroup
.SH SYNOPSIS
.B printrecallgroup
[
.BI -h
]
[
<recallGroupName>
[...]
]
.SH DESCRIPTION
.B printrecallgroup
prints out definitions of the given tape pools
.LP
.BI \-h,\ \-\-help
Get usage information
.TP
.BI <RecallGroupName>
when recall group names are given, only the definitions of the listed recall groups are printed.
If no recall group name is given, all recall group definitions are printed.
.SH EXAMPLES
.nf
.ft CW
# printrecallgroup
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
---------------------------------------------------------------------------------------------------------------------------
newrecallgroup 0 100GiB 1000 12h 0 263333 root 30-May-2012 17:29:12
default 20 100GiB 1000 12h 0 133068 2.1.13 upgrade script 03-May-2012 16:44:50
testrecallgroup 2 23MiB 1000 12h23mn 456 263419 root 30-May-2012 17:31:11
# printrecallgroup testrecallgroup nonexisting
NAME NBDRIVES MINAMOUNTDATA MINNBFILES MAXFILEAGE VDQMPRIORITY ID LASTEDITOR LASTEDITION
---------------------------------------------------------------------------------------------------------------------------
testrecallgroup 2 23MiB 1000 12h23mn 456 263419 root 30-May-2012 17:31:11
WARNING : the following recall groups do not exist : nonexisting
.SH NOTES
This command requires database client access to the stager catalogue.
Configuration for the database access is taken from castor.conf.
.SH SEE ALSO
.BR enterrecallgroup,
.BR modifyrecallgroup,
.BR deleterecallgroup,
.BR printdiskpool,
.BR printsvcclass,
.BR printfileclass,
.BR printtapepool,
.BR printmigrationroute,
.BR adminMultiInstance
.SH AUTHOR
\fBCASTOR\fP Team <castor.support@cern.ch>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment