#!/usr/bin/env python
# coding: utf-8
# Copyright (C) 1994-2018 Altair Engineering, Inc.
# For more information, contact Altair at www.altair.com.
#
# This file is part of the PBS Professional ("PBS Pro") software.
#
# Open Source License Information:
#
# PBS Pro 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.
#
# PBS Pro 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 program. If not, see .
#
# Commercial License Information:
#
# For a copy of the commercial license terms and conditions,
# go to: (http://www.pbspro.com/UserArea/agreement.html)
# or contact the Altair Legal Department.
#
# Altair’s dual-license business model allows companies, individuals, and
# organizations to create proprietary derivative works of PBS Pro and
# distribute them - whether embedded or bundled with other software -
# under a commercial license agreement.
#
# Use of Altair’s trademarks, including but not limited to "PBS™",
# "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
# trademark licensing policies.
import sys
import getopt
import logging
import logging.config
import os
import time
import re
import errno
import ptl
from ptl.utils.pbs_cliutils import CliUtils
from ptl.utils.pbs_logutils import PBSAccountingLog
from ptl.utils.pbs_dshutils import DshUtils
from ptl.lib.pbs_testlib import PtlConfig, BatchUtils, PbsTypeSize
from ptl.lib.pbs_testlib import Server, Scheduler, PbsStatusError
from ptl.lib.pbs_testlib import PTL_AND, PTL_OR, PTL_CLI
from ptl.lib.pbs_testlib import VNODE, JOB, SERVER, SCHED, RSC, QUEUE, HOOK
from ptl.lib.pbs_testlib import RESV, RESOURCES_AVAILABLE, RESOURCES_TOTAL
# trap SIGINT and SIGPIPE
def trap_exceptions(etype, value, tb):
sys.excepthook = sys.__excepthook__
if issubclass(etype, KeyboardInterrupt):
pass
elif issubclass(etype, IOError) and value.errno == errno.EPIPE:
pass
else:
sys.__excepthook__(etype, value, tb)
sys.excepthook = trap_exceptions
def usage():
msg = []
msg += ['Usage: ' + os.path.basename(sys.argv[0]).split('.pyc')[0]]
msg += [' [OPTION]\n\n']
msg += ['\tStatus and filter PBS entities on given attributes\n\n']
msg += ['\tNote: All output of this unsupported tool is experimental, \n']
msg += ['\tdo not rely on it remaining as-is across releases.\n\n']
msg += ['-A : Path to accounting log\n']
msg += ['-a : comma-separated list of attributes\n']
msg += [' attrs can be in key[OP]val format where OP is one ' +
'of <,<=,=,>=,>,~\n']
msg += ['-b: show available resources (a.k.a backfill hole)\n']
msg += ['-c: counts number of matching items\n']
msg += ['-C: counts grand total of given attribute values in complex\n']
msg += ['-d : path to diag directory\n']
msg += ['-j: report job equivalence classes\n']
msg += ['-n: report node equivalence classes\n']
msg += ['-r : comma-separated list of resource names, ' +
'e.g. ncpus, mem.\n']
msg += ['-s: show selected objects in qselect-like format\n']
msg += ['-t : target hostname\n']
msg += ['-T: report total resources available. Operates only on '
'equivalence classes\n']
msg += ['-U: show current utilization of the system, use -r to \n' +
' specify resources, default to ncpus, mem, nodes\n']
msg += ['--id=: identifier of the object to query\n']
msg += ['--key=: Accounting record key, one of Q or E\n']
msg += ['--user=: username to query for limits or '
'utilization\n']
msg += ['--group=: group to query for limits or '
'utilization\n']
msg += ['--project=: project to query for limits\n']
msg += ['--json: display object type information in json format.\n']
msg += ['--mode: show operating mode of PTL, one of cli or api\n']
msg += ['--cli: force stat to query PBS server over cli\n']
msg += ['--report-twiki: produce report in Twiki format\n']
msg += ['--nodes: operate on node\n']
msg += ['--queues: operate on queues\n']
msg += ['--jobs: operate on jobs\n']
msg += ['--resvs: operate on reservations\n']
msg += ['--server: operate on server\n']
msg += ['--scheduler: operate on scheduler\n']
msg += ['--report: produce a site report\n']
msg += ['--resources: operate on resources\n']
msg += ['--resource=: name of resource to stat\n']
msg += ['--resources-set: list resources set for a given object type\n']
msg += ['--fairshare-info=: query and display fairshare ' +
' info of entity\n']
msg += ['--fairshare-tree: query and display fairshare tree \n']
msg += ['--sline: show selected objects on a single line\n'
'\t will not affect output of --json, -j, -s, nor -n\n']
msg += ['--eval-formula: evaluate job priority\n']
msg += ['--include-running-jobs: include running jobs in formula'
' evaluation\n']
msg += ['--pports: show number of privileged ports in use\n']
msg += ['--resolve-indirectness: If set, dereference indirect '
' resources\n']
msg += ['--db-access=: file to credentials to access db\n']
msg += ['--limits-info: show limit information per entity and '
'object\n']
msg += ['--over-soft-limits: show entities that are over soft '
'limits\n']
msg += [
'--server-file=: path to file with output of qstat -Bf\n']
msg += ['--dedtime-file=: path to a dedicated time file\n']
msg += [
'--nodes-file=: path to file with output of pbsnodes -av\n']
msg += [
'--queues-file=: path to file with output of qstat -Qf\n']
msg += ['--jobs-file=: path to file with output of qstat -f\n']
msg += [
'--resvs-file=: path to file with output of pbs_rstat -f\n']
msg += ['--log-conf=: logging config file\n']
msg += ['--version: print version number and exit\n']
print "".join(msg)
class SiteReportFormatter:
def __init__(self, diag, version, sched_version, jeq, neq, utilization,
limits, qtypes, users, groups, sc, formula, backfill, hooks,
job_states, osrelease):
self.report_tm = time.ctime()
if diag and len(diag) > 1:
diag = diag.replace(".", "")
diag = diag.replace("/", "_")
diag = diag.replace("pbs_diag_", "")
if diag[0] in ('/', '_'):
diag = diag[1:]
m = re.search("(?P\d{6}_\d{6})", diag)
if m:
_tm = m.group("dtm")
_kt = time.mktime(time.strptime(_tm, "%y%m%d_%H%M%S"))
self.report_tm = time.ctime(_kt)
self.diag = diag
self.version = version
self.sched_version = sched_version
self.jeq = sorted(jeq, key=lambda e: len(e.entities))
self.neq = sorted(neq, key=lambda e: len(e.entities))
self.utilization = utilization
self.limits = limits
self.qtypes = qtypes
self.users = users
self.groups = groups
self.sc = sc
self.formula = formula
self.backfill = backfill
self.hooks = hooks
self.job_states = job_states
self.delim = "\n"
self.open_tag = []
self.close_tag = []
def __twiki__(self):
self.delim = "---+++++"
self.open_tag = [""]
self.close_tag = [""]
return self.__str__()
def __str__(self):
title = 'PBS Pro cluster report on ' + self.report_tm
if len(self.open_tag) == 0 or self.diag is None:
msg = []
self.sep = ['-' * len(title)]
else:
msg = ["---+++" + str(self.diag)]
self.sep = []
msg += [title]
msg += self.sep
msg += [self.delim + 'PBS Pro version']
msg += self.sep
msg += self.open_tag
if self.version == self.sched_version:
msg += [self.version]
else:
msg += ['Server: ' + self.version]
msg += ['Scheduler: ' + self.sched_version]
msg += self.close_tag
if osrelease is not None:
msg += [self.delim + 'OS release']
msg += self.sep
msg += self.open_tag
msg += [osrelease]
msg += self.close_tag
msg += [self.delim + 'Utilization']
msg += self.sep
msg += self.open_tag
msg += u
msg += self.close_tag
msg += [self.delim + 'Job States']
msg += self.sep
msg += self.open_tag
for k, v in self.job_states.items():
msg += ["%s: %d" % (k.split('=')[1], v)]
msg += self.close_tag
if self.limits:
qsl = ssl = qhl = shl = 0
if SERVER in self.limits:
for l in self.limits[SERVER]:
if '_soft' in l.limit_type:
ssl += 1
else:
shl += 1
if QUEUE in self.limits:
for l in self.limits[QUEUE]:
if '_soft' in l.limit_type:
qsl += 1
else:
qhl += 1
msg += [self.delim + 'Limits']
msg += self.sep
msg += self.open_tag
msg += ["Queue soft limits: %d" % qsl]
msg += ["Queue hard limits: %d" % qhl]
msg += ["Server soft limits: %d" % ssl]
msg += ["Server hard limits: %d" % shl]
msg += self.close_tag
msg += [self.delim + 'Queue types']
msg += self.sep
msg += self.open_tag
for k, v in qtypes.items():
msg += ["%s: %d" % (k.split('=')[1], v)]
msg += self.close_tag
msg += [self.delim + 'Number of users and groups']
msg += self.sep
msg += self.open_tag
msg += ["users: %d" % (users)]
msg += ["groups: %d" % (groups)]
msg += self.close_tag
if self.hooks:
msg += [self.delim + 'Hooks']
msg += self.sep
msg += self.open_tag
msg += self.hooks
msg += self.close_tag
msg += [self.delim + 'Scheduling policies']
msg += self.sep
msg += self.open_tag
if 'preemptive_sched' in sc:
msg += ["preemption: %s" % sc['preemptive_sched']]
if 'backfill' in sc:
msg += ["backfilling: %s" % sc['backfill']]
if 'fair_share' in sc:
msg += ["fair share: %s" % sc['fair_share']]
if formula is not None:
msg += ["formula: %s" % self.formula]
if backfill is not None:
msg += ["backfill depth: %s" % self.backfill]
msg += self.close_tag
msg += [self.delim + 'Node Equivalence Classes']
msg += self.sep
msg += self.open_tag
for e in self.neq:
msg += [str(e)]
msg += self.close_tag
msg += [self.delim + 'Job Equivalence Classes']
msg += self.sep
msg += self.open_tag
for e in self.jeq:
msg += [str(e)]
msg += self.close_tag
return "\n".join(msg)
def utilization_to_str(u):
msg = []
for k, v in u.items():
if len(v) != 2:
continue
if v[1] == 0:
perc = 100
else:
perc = 100 * v[0] / v[1]
if 'mem' in k:
v[0] = PbsTypeSize(str(v[0]) + 'kb')
v[1] = PbsTypeSize(str(v[1]) + 'kb')
msg += [k + ': (' + str(v[0]) + '/' + str(v[1]) + ') ' +
str(perc) + '%']
else:
msg += [k + ': (' + str(v[0]) + '/' + str(v[1]) + ') ' +
str(perc) + '%']
return msg
if __name__ == '__main__':
if len(sys.argv) < 2:
usage()
sys.exit(1)
diag = None
lvl = logging.ERROR
hostname = None
objtype = None
jobclasses = False
nodeclasses = False
attributes = None
backfillhole = None
attrop = PTL_OR
accumulate = False
grandtotal = False
inputfile = {}
qselectfmt = False
resources = None
utilization = False
fsusage_entity = None
fstree = False
fsentity = None
fsperc_entity = None
pbsfs = False
eval_formula = False
entity = {}
objid = None
resourcesset = None
dedtimefile = None
limits_info = False
over_soft_limits = False
json_on = False
pports = False
db_access = None
logconf = None
scheduler = None
server = None
report = False
report_twiki = False
force_cli = False
get_mode = False
fmt = {'%6': '\n'}
acct = None
key = 'E'
indirectness = False
osrelease = None
include_running_jobs = False
restotal = RESOURCES_AVAILABLE # equivalence classes report avail - assgnd
lopts = ["nodes", "queues", "server", "scheduler", "jobs", "resvs"]
lopts += ["fairshare-tree", "eval-formula", "user=", "group=", "project="]
lopts += ["fairshare-info=", "resource=", "resources-set", "nodes-file="]
lopts += ["queues-file=", "jobs-file=", "resvs-file=", "server-file="]
lopts += ["dedtime-file=", "limits-info", "json", "pports", "db-access="]
lopts += ["over-soft-limits", "id=", "resources", "log-conf=", "version"]
lopts += ["mode", "cli", "report", "sline", "key=", "resolve-indirectness"]
lopts += ["report-twiki", "include-running-jobs"]
try:
opts, args = getopt.getopt(sys.argv[1:], "a:A:d:l:r:t:fUbcChjnsT",
lopts)
except:
logging.error('unhandled option')
usage()
sys.exit(1)
for o, val in opts:
if o == '-a':
attributes = val
elif o == '-A':
acct = CliUtils.expand_abs_path(val)
elif o == '-b':
backfillhole = True
objtype = VNODE
elif o == '-c':
accumulate = True
elif o == '-C':
grandtotal = True
elif o == '-d':
diag = CliUtils.expand_abs_path(val)
if not os.path.isdir(diag):
sys.stderr.write('Cannnot access diag at ' + str(diag) + '\n')
sys.exit(1)
elif o == '-j':
jobclasses = True
elif o == '-l':
lvl = CliUtils().get_logging_level(val)
elif o == '-n':
nodeclasses = True
elif o == '-r':
resources = val
elif o == '-s':
qselectfmt = True
elif o == '-t':
hostname = val
elif o == '-U':
utilization = True
elif o == '-h':
usage()
sys.exit(0)
elif o == '--cli':
force_cli = True
elif o == '--key':
key = val
elif o == '--id':
objid = val
elif o == '--sline':
fmt = {'%1': ': ', '%2': '', '%3': '=', '%4': ', ', '%5': '\n'}
elif o == "--pports":
pports = True
elif o == '--version':
print ptl.__version__
sys.exit(0)
elif o == "--user":
entity['euser'] = val
elif o == "--group":
entity['egroup'] = val
elif o == "--mode":
get_mode = True
elif o == "--project":
entity['project'] = val
elif o == "--fairshare-info":
fsentity = val
fstree = True
elif o == "--fairshare-tree":
fstree = True
elif o == "--eval-formula":
eval_formula = True
elif o == '--include-running-jobs':
include_running_jobs = True
elif o == "--db-access":
db_access = CliUtils.expand_abs_path(val)
elif o == "--json":
json_on = True
elif o == "--limits-info":
limits_info = True
elif o == "--over-soft-limits":
over_soft_limits = True
elif o == "--log-conf":
logconf = val
elif o == "--nodes":
objtype = VNODE
elif o == "--queues":
objtype = QUEUE
elif o == "--jobs":
objtype = JOB
elif o == "--resvs":
objtype = RESV
elif o == "--server":
objtype = SERVER
elif o == "--scheduler":
objtype = SCHED
elif o == "--report":
report = True
elif o == "--report-twiki":
report_twiki = True
elif o == "--resources":
objtype = RSC
elif o == "--resource":
objtype = RSC
objid = val
elif o == "--resources-set":
resourcesset = True
elif o == "--resolve-indirectness":
indirectness = True
elif o == "--nodes-file":
objtype = VNODE
inputfile[VNODE] = CliUtils.expand_abs_path(val)
elif o == "--queues-file":
objtype = QUEUE
inputfile[QUEUE] = CliUtils.expand_abs_path(val)
elif o == "--jobs-file":
objtype = JOB
inputfile[JOB] = CliUtils.expand_abs_path(val)
elif o == "--resvs-file":
objtype = RESV
inputfile[RESV] = CliUtils.expand_abs_path(val)
elif o == "--server-file":
objtype = SERVER
inputfile[SERVER] = CliUtils.expand_abs_path(val)
elif o == "--dedtime-file":
dedtimefile = CliUtils.expand_abs_path(val)
elif o == '-T':
restotal = None
else:
sys.stderr.write("Unrecognized option")
usage()
sys.exit(1)
PtlConfig()
if pports:
msg = CliUtils().priv_ports_info(hostname)
if not msg:
sys.exit(1)
print "\n".join(msg)
sys.exit(0)
if logconf:
logging.config.fileConfig(logconf)
else:
logging.basicConfig(level=lvl)
bu = BatchUtils()
if len(inputfile) > 0:
server = Server(diagmap=inputfile, db_access=db_access)
elif diag is not None or db_access is not None:
server = Server(hostname, diag=diag, db_access=db_access)
scheduler = Scheduler(server=server, diag=diag, db_access=db_access)
else:
if hostname is None:
if 'PBS_SERVER' in os.environ:
_h = os.environ['PBS_SERVER']
else:
if 'PBS_CONF_FILE' in os.environ:
_c = DshUtils().parse_pbs_config(
file=os.environ['PBS_CONF_FILE'])
elif os.path.isfile('/etc/pbs.conf'):
_c = DshUtils().parse_pbs_config()
if 'PBS_SERVER' in _c:
_h = _c['PBS_SERVER']
else:
_h = None
else:
_h = hostname
server = Server(_h, stat=False)
if force_cli:
if server.get_op_mode() != PTL_CLI:
server.set_op_mode(PTL_CLI)
if get_mode:
print server.get_op_mode()
sys.exit(0)
if dedtimefile:
if scheduler is None:
scheduler = Scheduler(
server=server, diag=diag, db_access=db_access)
scheduler.set_dedicated_time_file(dedtimefile)
# server is assumed up in diag mode
if not server.isUp() and objtype != RSC and\
not db_access:
logging.error('PBS Server is down, exiting')
sys.exit(1)
if report or report_twiki:
jobs = server.status(JOB)
nodes = server.status(VNODE)
queues = server.status(QUEUE)
jeq = server.equivalence_classes(JOB, bslist=jobs)
if scheduler is not None:
res = scheduler.get_resources(exclude=['host', 'vnode', 'arch'])
if res:
for i in range(len(res)):
res[i] = "resources_available." + str(res[i])
else:
res = ['resources_available.ncpus', 'resources_available.mem']
neq = server.equivalence_classes(VNODE, res, bslist=nodes,
show_zero_resources=True,
op=RESOURCES_TOTAL,
resolve_indirectness=indirectness)
job_states = server.counter(JOB, 'job_state', bslist=jobs)
u = utilization_to_str(server.utilization(entity=entity, nodes=nodes,
jobs=jobs))
lims = server.parse_all_limits(
server=[server.attributes], queues=queues)
qtypes = server.counter(QUEUE, 'queue_type', bslist=queues)
d = server.counter(JOB, ['euser', 'egroup'], bslist=jobs)
users = groups = 0
for k, v in d.items():
if 'euser' in k:
users += 1
elif 'egroup' in k:
groups += 1
if scheduler is None:
scheduler = Scheduler(server=server, diag=server.diag,
diagmap=server.diagmap)
sc = scheduler.sched_config
formula = backfill = None
version = 'unavailable'
sched_version = 'unavailable'
hooks = []
_hlist = server.status(HOOK)
for hook in _hlist:
if (not hook['id'].startswith('PBS_translate_mpp') and
not hook['id'].startswith('PBS_ibwins') and
not hook['id'].startswith('PBSadd_spawn')):
if 'enabled' in hook and hook['enabled'] == 'false':
_disabled = '[disabled]'
else:
_disabled = ''
hooks.append(hook['id'] + ': ' + hook['event'] + ' ' +
_disabled)
try:
if 'pbs_version' not in server.attributes:
d = server.status(SERVER, ['pbs_version', 'job_sort_formula',
'backfill_depth'])
else:
d = [server.attributes]
if 'job_sort_formula' in d[0]:
formula = d[0]['job_sort_formula']
if 'backfill_depth' in d[0]:
backfill = d[0]['backfill_depth']
if 'pbs_version' in d[0]:
version = d[0]['pbs_version']
except PbsStatusError:
pass
try:
server.status(SCHED, 'pbs_version')
except PbsStatusError:
pass
if d and 'pbs_version' in d[0]:
sched_version = d[0]['pbs_version']
if diag is not None:
f = os.path.join(diag, 'OSrelease')
if os.path.isfile(f):
fos = open(f)
osrelease = fos.readline()
fos.close()
sr = SiteReportFormatter(diag, version, sched_version, jeq, neq, u,
lims, qtypes, users, groups, sc, formula,
backfill, hooks, job_states, osrelease)
if report_twiki:
print str(sr.__twiki__())
else:
print str(sr)
sys.exit(0)
if utilization:
if resources:
resources = resources.split(',')
u = server.utilization(resources, entity=entity)
msg = utilization_to_str(u)
if msg:
print "\n".join(msg)
sys.exit(0)
if fstree:
if scheduler is None:
scheduler = Scheduler(server=server, diag=server.diag,
diagmap=server.diagmap, db_access=db_access)
fs_as_bs = scheduler.fairshare_tree.__batch_status__()
if json_on:
print CliUtils.__json__(fs_as_bs)
else:
scheduler.utils.show(fs_as_bs, fsentity)
sys.exit(0)
if eval_formula:
f = server.evaluate_formula(include_running_jobs=include_running_jobs)
if f:
d = server.status(SERVER, 'job_sort_formula')
print 'Formula: ' + d[0]['job_sort_formula']
ret = sorted(f.items(), key=lambda x: x[1][1], reverse=True)
for (jobid, (fml, val)) in ret:
print jobid + ': ' + fml + ' = ' + str(val)
sys.exit(0)
# parse resources and attributes 'language', i.e., handling of && and ||
if resources is not None:
if objtype in (JOB, RESV):
_r = "Resource_List."
else:
_r = "resources_available."
# add the resources to any attributes that may have been specified
if attributes is None:
attributes = ''
else:
attributes += ","
if "&&" in resources:
attrop = PTL_AND
resources = resources.replace("&&", ",")
elif "||" in resources:
resources = resources.replace("||", ',')
attributes += ",".join(map(lambda n: _r + n, resources.split(',')))
if attributes is not None:
attributes = attributes.replace(" ", "")
if "&&" in attributes:
attrop = PTL_AND
attributes = attributes.replace("&&", ",")
elif "||" in attributes:
attributes = attributes.replace("||", ',')
attributes = attributes.split(",")
if attributes:
setattrs = False
operators = ('<=', '>=', '!=', '=', '>', '<', '~')
for a in attributes:
for op in operators:
if op in a:
setattrs = True
break
d = bu.convert_attributes_by_op(attributes, setattrs)
if len(d) > 0:
attributes = d
if backfillhole is not None:
server.show_whats_available(attrib=attributes)
sys.exit(0)
# other than the backfill hole that requires working with server objects,
# since updating object attributes can be an expensive operation on large
# systems, we disable it on these select calls where they are needed
server.ptl_conf['update_attributes'] = False
if limits_info or over_soft_limits:
etype = None
ename = None
if 'euser' in entity:
etype = 'u'
ename = entity['euser']
elif 'egroup' in entity:
etype = 'g'
ename = entity['egroup']
elif 'project' in entity:
etype = 'p'
ename = entity['project']
linfo = server.limits_info(etype=etype,
ename=ename,
db_access=db_access,
over=over_soft_limits)
if json_on:
CliUtils.__json__(server.utils.decode_dictlist(linfo))
else:
server.utils.show(linfo)
sys.exit(0)
if nodeclasses:
if scheduler is None and os.getuid() == 0:
scheduler = Scheduler(server=server, diag=server.diag,
diagmap=server.diagmap, db_access=db_access)
if attributes:
res = attributes
elif scheduler is not None:
res = scheduler.get_resources(exclude=['host', 'vnode', 'arch'])
if res:
# ncpus and mem may have been removed from the resources line
# in which case we must add them back
if 'ncpus' not in res:
res.append('ncpus')
if 'mem' not in res:
res.append('mem')
for i in range(len(res)):
res[i] = "resources_available." + str(res[i])
else:
res = ['resources_available.ncpus', 'resources_available.mem']
server.show_equivalence_classes(None, VNODE, res, op=restotal,
show_zero_resources=True,
db_access=db_access,
resolve_indirectness=indirectness)
if jobclasses or acct is not None:
if acct is not None:
eqclasses = {}
# no need to ping a live server, so pretend
sm = {SERVER: None}
# disable logging to avoid displaying server instatiation messages
logging.disable(logging.INFO)
server = Server('__diagserver__', diagmap=sm)
logging.disable(logging.NOTSET)
alog = PBSAccountingLog(show_progress=True)
alog.enable_accounting_workload_parsing()
alog.analyze(acct)
attrs = alog.job_attrs.values()
eq = server.equivalence_classes(JOB, attributes, bslist=attrs)
server.show_equivalence_classes(eq)
if alog.parser_errors > 0:
print 'Failed to parse: ' + str(alog.parser_errors)
sys.exit(0)
else:
server.show_equivalence_classes(None, JOB, attributes, op=restotal,
db_access=db_access)
# remaining operations are to filter an object type, skip if an
# equivalence class or resource was requested
if (jobclasses or nodeclasses):
sys.exit(0)
if restotal is None:
logging.error('-T option operates only an equivalence classes')
sys.exit(1)
if resourcesset is not None:
if objtype is None:
logging.error('no object type specified')
sys.exit(1)
res = bu.list_resources(objtype, server.status(objtype))
if res:
print "\n".join(res)
sys.exit(0)
if (accumulate or grandtotal) and (attributes is not None):
if objtype is None:
logging.error('no object type specified')
sys.exit(1)
d = server.counter(objtype, attributes, attrop=attrop,
grandtotal=grandtotal, db_access=db_access,
extend='t', resolve_indirectness=indirectness)
for k, v in d.items():
if grandtotal and 'mem' in k:
d[k] = PbsTypeSize().encode(value=v)
else:
d[k] = v
else:
if objtype is None:
logging.error('no object type specified')
sys.exit(1)
idonly = True
if not qselectfmt:
idonly = False
if attributes:
d = server.filter(objtype, attributes, attrop=attrop,
idonly=idonly, id=objid, extend='t',
db_access=db_access, grandtotal=grandtotal,
resolve_indirectness=indirectness)
else:
statinfo = server.status(objtype, id=objid, extend='t',
db_access=db_access,
resolve_indirectness=indirectness)
if json_on:
print CliUtils.__json__(server.utils.decode_dictlist(statinfo))
else:
server.utils.show(statinfo, fmt=fmt)
sys.exit(0)
if not d:
sys.exit(0)
if not qselectfmt and not (grandtotal or accumulate):
if objtype is None:
logging.error('no object type specified')
sys.exit(1)
visited = []
toshow = []
for objs in d.values():
for obj in objs:
if obj['id'] in visited:
continue
else:
toshow.append(obj)
visited.append(obj['id'])
if json_on:
CliUtils.__json__(server.utils.decode_dictlist(toshow))
else:
server.utils.show(toshow, fmt=fmt)
elif attrop == PTL_AND and len(d) > 0:
if objtype is None:
logging.error('no object type specified')
sys.exit(1)
if isinstance(attributes, (list, dict)):
if grandtotal:
for k, v in d.items():
print k + ": " + str(v)
elif accumulate:
print " && ".join(d.keys()) + ": " + str(d.values()[0])
else:
print " && ".join(d.keys()) + ": \n" + \
"\n".join(str(d.values()[0]))
else:
print str(" && ".join(d.keys())) + ": " + str(d.values()[0])
else:
if objtype is None:
logging.error('no object type specified')
sys.exit(1)
for k, v in d.items():
if isinstance(v, list):
print k + ":"
for val in v:
print val
else:
print k + ":" + str(v)