Changeset 248


Ignore:
Timestamp:
08/16/10 16:53:49 (14 years ago)
Author:
bas
Message:

a new imporved new_rack_pbsmon.py. Thanks to Dennis Stam (SARA)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/examples/new_rack_pbsmon.py

    r239 r248  
    11#! /usr/bin/env python
    22#
    3 #       pbsmon  WJ104
     3# This version of pbsmon is base on the new_rack_pbsmon.py
     4#
     5# Authors:
     6#   Bas van der Vlies
     7#   Dennis Stam
    48#
    5 #       * added START_RACK BvdV
    6 #       * added Total, pbs_serial_free and pbs_parallel free, BvdV
     9#      SVN Info:
     10#              $Id$
     11#              $URL$
    712#
    8 #       Hint: set ts=4
    9 #
    10 #       SVN Info:
    11 #               $Id$
    12 #
    13 import os
     13
     14"""
     15Usage: pbsmon [hosts]....
     16
     17Specifying hostnames:
     18  To specify a range use the [] to indicate a range, a couple of examples:
     19
     20  The first five nodes of rack 16
     21      - gb-r16n[1-5]
     22
     23  The first five nodes and node 12 and 18 of rack 16 to 20
     24      - gb-r[16-20]n[1-5,12,18]
     25
     26  The first five nodes de in rack 16 with padding enabled
     27      - gb-r[16]n[01-5]
     28
     29The ranges ([]) are not only limited to numbers, letters can also be used.
     30"""
     31
    1432import sys
    15 import string
    16 import getopt
    1733import re
     34import re
     35import types
     36from optparse import OptionParser
    1837
    1938import pbs
    2039from PBSQuery import PBSQuery
    2140from PBSQuery import PBSError
     41
     42# Remark: When both are True, extended view is being printed
     43PRINT_TABLE = True
     44PRINT_EXTENDED = False
     45
     46# Which nodes must be skipped
     47EXCLUDE_NODES = [ 'login' ]
     48
     49# Some global OPTS
     50OPT_SKIP_EMPTY_RACKS = True
     51OPT_SERVERNAME = None
     52
     53## Begin: TABLE view opts
    2254
    2355# A node has the following syntax gb-r10n10
     
    2759# number of nodes and racks
    2860#
    29 NODE_EXPR = re.compile(r"""
    30         (?P<racknr>r[0-9]+)
    31         (?P<nodenr>n[0-9]+)
    32 """, re.VERBOSE)
    33 
    34 SKIP_CHARS_RACK = 1
    35 SKIP_CHARS_NODE = 1
    36 
    37 START_RACK = 1
    38 
    39 pbs_ND_single                   = 'job (single)'
    40 pbs_ND_total                    = 'total'
    41 pbs_ND_free_serial              = 'free serial'
    42 pbs_ND_free_parallel    = 'free parallel'
     61NODE_EXPR = "gb-r(?P<racknr>[0-9]+)n(?P<nodenr>[0-9]+)"
     62
     63START_RACK = 1
     64
     65## End: TABLE view opts
     66
     67## Begin: EXTENDED view opts
     68
     69LENGTH_NODE  = 0
     70LENGTH_STATE = 0
     71
     72EXTENDED_PATTERNS = {
     73    'header' : ' %-*s | %-*s | %s',
     74    'row': ' %-*s | %-*s | %s',
     75    'line': ' %s',
     76    'line_char': '-',
     77}
     78
     79## End: EXTENDED view opts
     80
     81pbs_ND_single           = 'job (single)'
     82pbs_ND_total            = 'total'
     83pbs_ND_free_serial      = 'free serial'
     84pbs_ND_free_parallel    = 'free parallel'
    4385
    4486PBS_STATES = {
    45         pbs.ND_free                             : '_',
    46         pbs.ND_down                             : 'X',
    47         pbs.ND_offline                  : '.',
    48         pbs.ND_reserve                  : 'R',
    49         pbs.ND_job_exclusive    : 'J',
    50         pbs.ND_job_sharing              : 'S',
    51         pbs.ND_busy                             : '*',
    52         pbs.ND_state_unknown    : '?',
    53         pbs.ND_timeshared               : 'T',
    54         pbs.ND_cluster                  : 'C',
    55         pbs_ND_single                   : 'j',
    56         pbs_ND_free_serial              : '_',
    57         pbs_ND_free_parallel    : '_',
    58         pbs_ND_total                    : ' '
     87    pbs.ND_free             : '_',
     88    pbs.ND_down             : 'X',
     89    pbs.ND_offline          : '.',
     90    pbs.ND_reserve          : 'R',
     91    pbs.ND_job_exclusive    : 'J',
     92    pbs.ND_job_sharing      : 'S',
     93    pbs.ND_busy             : '*',
     94    pbs.ND_state_unknown    : '?',
     95    pbs.ND_timeshared       : 'T',
     96    pbs.ND_cluster          : 'C',
     97    pbs_ND_single           : 'j',
     98    pbs_ND_free_serial      : '_',
     99    pbs_ND_free_parallel    : '_',
     100    pbs_ND_total            : ' '
    59101}
    60102
    61 # command line options
    62 OPT_NODESTATUS = 1
    63 OPT_SUMMARY = 0
    64 OPT_SERVERNAME = None
    65 OPT_SKIP_EMPTY_RACKS = 1
    66 
    67 
    68 def parse_hostname(id):
    69         """
    70         Determiine the the limits of the cluster:
    71           - How many racks are in the cluster
    72           - What is the max amount of nodes per rack
    73         """
    74         result = NODE_EXPR.search(id)
    75         if result:
    76                 r = int(result.group('racknr')[SKIP_CHARS_RACK:])
    77                 n = int(result.group('nodenr')[SKIP_CHARS_NODE:])
    78 
    79         return (r,n)
    80                
    81 
    82 def pbsmon(server = None):
    83         global PBS_STATES
    84 
    85         try:
    86                 if not server:
    87                         p = PBSQuery()
    88                 else:
    89                         p = PBSQuery(server)
    90         except PBSError, reason:
    91                 print 'error: %s' % reason
    92                 sys.exit(-1)
    93 
    94         p.new_data_structure()
    95 
    96 # get the state of the nodes
    97         attr = [ 'state', 'jobs', 'properties' ]
    98 
    99         try:
    100                 nodes = p.getnodes(attr)
    101         except PBSError, reason:
    102                 print 'error: %s' % reason
    103                 sys.exit(-1)
    104 
    105         node_dict = {}
    106 
    107         number_of_racks = nodes_per_rack = 0
    108         #determine_limits(nodes)
    109 
    110         for id in nodes:
    111 
    112                 # Skip login nodes in status display
    113                 #
    114                 if not nodes[id].name.find('login'):
    115                         continue
    116 
    117                 if pbs.ND_down in nodes[id].state:
    118                         state = pbs.ND_down
    119                 else:
    120                         state = nodes[id].state[0]
    121 
    122                 state_char = PBS_STATES[state]
    123 
    124                 #print 'TD: ', nodes[id].name, nodes[id].is_free() ,nodes[id].has_job()
    125 
    126                 if nodes[id].is_free() and nodes[id].has_job():         # single job
    127                         #print 'TD: %s' % id, nodes[id]
    128                         state_char = PBS_STATES[pbs_ND_single]
    129 
    130                 #print 'TD: %s %s' % (id, state_char)
    131 
    132                 racknr, nodenr = parse_hostname(id)
    133 
    134                 if racknr > number_of_racks:
    135                         number_of_racks = racknr
    136 
    137                 if nodenr > nodes_per_rack:
    138                         nodes_per_rack = nodenr
    139 
    140                 try:
    141                         node_dict[racknr][nodenr] = state_char
    142                 except KeyError:
    143                         node_dict[racknr] = dict()
    144                         node_dict[racknr][nodenr] = state_char
    145                        
    146 
    147 # print header lines
    148         save_column = None
    149         print '  ',
    150         for rack in xrange(START_RACK, number_of_racks + 1):
    151 
    152                 if not (rack % 10):
    153                         char = '%d' %(rack/10)
    154                         save_column = char
    155                 else:
    156                         char = ' '
    157 
    158                 if OPT_SKIP_EMPTY_RACKS:
    159                         if node_dict.has_key(rack):
    160                                 if save_column:
    161                                         char = save_column
    162                                         save_column = None
    163 
    164                                 print char,
    165                 else:
    166                         print char,
    167         print
    168 
    169         print '  ',
    170         for rack in xrange(START_RACK, number_of_racks + 1):
    171                
    172                 char = rack % 10
    173                 if OPT_SKIP_EMPTY_RACKS:
    174                         if node_dict.has_key(rack):
    175                                 print char,
    176                 else:
    177                         print char,
    178         print
    179 
    180 
    181         for node_nr in xrange(1, nodes_per_rack + 1):
    182                 print '%2d' % node_nr,
    183 
    184                 for rack in xrange(START_RACK, number_of_racks + 1):
    185 
    186                         if OPT_SKIP_EMPTY_RACKS:
    187                                 if not node_dict.has_key(rack):
    188                                         continue
    189                         try:
    190                                 print node_dict[rack][node_nr],
    191                         except KeyError:
    192                                 print ' ',
    193                 print
    194 
     103###### Some Useful Class ##################
    195104#
    196 #       summary() counts the number of nodes in a particular state
     105# Author: Dennis Stam
     106# Date  : 09-04-2009
     107# Desc. : This class allows you use ranges within the given arguments. Very
     108#         useful for specifying mutliple hosts. This class extends the
     109#         OptionParser class.
    197110#
    198 def pbsmon_summary(server = None):
    199         global PBS_STATES
    200 
    201         try:
    202                 if not server:
    203                         p = PBSQuery()
    204                 else:
    205                         p = PBSQuery(server)
    206         except PBSQuery.PBSError, reason:
    207                 print 'error: %s' % reason
    208                 sys.exit(-1)
    209 
    210 # get the state of the nodes
    211         attr = [ 'state', 'jobs', 'properties' ]
    212         try:
    213                 nodes = p.getnodes(attr)
    214         except PBSError, reason:
    215                 print 'error: %s' % reason
    216                 sys.exit(-1)
    217 
    218         node_dict = {}
    219 
    220         count_states = {}
    221         for key in PBS_STATES.keys():
    222                 count_states[key] = 0
    223 
    224         for nodename, node in nodes.items():
    225 
    226                 # Skip login nodes in status display
    227                 #
    228                 if not nodename.find('login'):
    229                         continue
    230 
    231                 # A node can have multiple states
    232                 state = node['state'][0]
    233 
    234                 state_char = PBS_STATES[state]
    235                 count_states[state] += 1
    236                 count_states[pbs_ND_total] += 1
    237 
    238                 if node.is_free():                                                      # can happen for single CPU jobs
    239                         if node.has_job():
    240 #                               print 'TD: %s' % nodename, node
    241                                 state_char = PBS_STATES[pbs_ND_single]
    242                                 count_states[pbs.ND_free] -=  1
    243                                 count_states[pbs_ND_single] += 1
    244                         else:
    245                                 if  'infiniband' in node['properties']:
    246                                         count_states[pbs_ND_free_parallel] +=  1
    247                                 elif  'gigabit' in node['properties']:
    248                                         count_states[pbs_ND_free_serial] +=  1
    249                                 #else:
    250                                 #       count_states[pbs_ND_free_serial] +=  1
    251                                
    252 #               print 'TD: %s %s' % (nodename, state_char)
    253                 dummy = string.split(nodename, '-')
    254                 node_dict[dummy[1]] = state_char
    255 
    256         legend = PBS_STATES.keys()
    257         legend.sort()
    258 
    259         n = 0
    260         for state in legend:
    261                 print '  %s  %-13s : %-5d' % (PBS_STATES[state], state, count_states[state]),
    262 
    263                 n = n + 1
    264                 if not (n & 1):
    265                         print
    266 
    267 
    268 def pbsmon_legend():
    269         global PBS_STATES
    270 
    271         legend = PBS_STATES.keys()
    272         legend.sort()
    273 
    274         n = 0
    275         for state in legend:
    276                 if state == 'total':
    277                         continue
    278 
    279                 print '  %s  %-20s' % (PBS_STATES[state], state),
    280 
    281                 n = n + 1
    282                 if not (n & 1):
    283                         print
    284 
    285 
    286 def usage():
    287         global PROGNAME
    288 
    289         print 'usage: %s [options]' % PROGNAME
    290         print '%s displays the status of the nodes in the batch system' % PROGNAME
    291         print
    292         print 'Options:'
    293         print '  -h, --help             Show this information'
    294         print '  -s, --summary          Display only a short summary'
    295         print '  -a, --all              Display both status and summary'
    296         print '  -w, --wide             Wide display for node status'
    297         print '  -S, --server=<server>  Use a different PBS/Torque server'
    298         print
    299         print 'Legend:'
    300 
    301         pbsmon_legend()
    302        
    303 
    304 def getopts():
    305         global PROGNAME, OPT_NODESTATUS, OPT_SUMMARY, OPT_SKIP_EMPTY_RACKS, OPT_SERVERNAME
    306 
    307         if len(sys.argv) <= 1:
    308                 return
    309 
    310         try:
    311                 opts, args = getopt.getopt(sys.argv[1:], 'hsawS:', ['help','summary', 'all', 'wide', 'server='])
    312         except getopt.error, reason:
    313                 print '%s: %s' % (PROGNAME, reason)
    314                 usage()
    315                 sys.exit(1)
    316 
    317         except getopt.GetoptError, reason:
    318                 print '%s: %s' % (PROGNAME, reason)
    319                 usage()
    320                 sys.exit(1)
    321 
    322         except:
    323                 usage()
    324                 sys.exit(1)
    325 
    326         server = None
    327         errors = 0
    328 
    329         for opt, arg in opts:
    330                 if opt in ('-h', '--help', '-?'):
    331                         usage()
    332                         sys.exit(1)
    333 
    334                 if opt in ('-s', '--summary'):
    335                         OPT_SUMMARY = 1
    336                         OPT_NODESTATUS = 0
    337                         continue
    338 
    339                 if opt in ('-a', '--all'):
    340                         OPT_SUMMARY = 1
    341                         OPT_NODESTATUS = 1
    342                         continue
    343 
    344                 if opt in ('-w', '--wide'):
    345                         OPT_SKIP_EMPTY_RACKS = 0
    346                         continue
    347 
    348                 if opt in ('-S', '--server'):
    349                         OPT_SERVERNAME = arg
    350                         continue
    351 
    352                 print "%s: unknown command line option '%s'" % (PROGNAME, opt)
    353                 errors = errors + 1
    354 
    355         if errors:
    356                 usage()
    357                 sys.exit(1)
    358 
     111# SVN Info:
     112#       $Id$
     113#
     114
     115class AdvancedParser(OptionParser):
     116        """
     117        This class extends from OptionParser, where the method check_values has been
     118        overrided.
     119
     120        In this function a extra parsing is done on the the rest of the arguments. This
     121        extra parsing is the creating of multiple hostnames from a pattern/range.
     122
     123        When a user specifies this argument dr-r[15,17-20]n[1-5,10] then this class
     124        returns 24 hosts. Besides using numbers you can also specify lower cased
     125        letters from a-z.
     126
     127        Doctest:
     128        >>> parser = AdvancedParser()
     129        >>> parser.return_range('12-15,20')
     130        [12, 13, 14, 15, '20']
     131
     132        >>> option, args = parser.parse_args(['dr-r7n[1-5]'])
     133        >>> print args
     134        ['dr-r7n1', 'dr-r7n2', 'dr-r7n3', 'dr-r7n4', 'dr-r7n5']
     135        """
     136
     137        def return_range(self, string):
     138                """
     139                This method uses the given numbers and converts them to ranges. When
     140                ower cased letters are specified they will be converted to integer
     141                ordinal of a one-character string.
     142                (ie. a = 97, z = 122)
     143
     144                The ranges will be return as lists
     145                """
     146                parts = string.split( ',' )
     147                numbers_chars = list()
     148                equal_width_length = 0
     149
     150                for part in parts:
     151                        part_range = part.split( '-' )
     152                        if len( part_range ) == 2:
     153                                try:
     154                                        if part_range[0][0] == '0' or part_range[1][0] == '0':
     155                                                if len( part_range[0] ) > len( part_range[1] ):
     156                                                        equal_width_length = len( part_range[0] )
     157                                                else:
     158                                                        equal_width_length = len( part_range[1] )
     159
     160                                        numbers_chars += range( int( part_range[0] ), int( part_range[1] ) + 1 )
     161                                except ValueError:
     162                                        begin = ord( part_range[0] )
     163                                        end = ord( part_range[1] )
     164                                        tmplist = list()
     165
     166                                        if begin > 96 and end < 123:
     167                                                tmplist = range( begin, end + 1)
     168
     169                                                for letter in tmplist:
     170                                                        numbers_chars.append( chr( letter ) )
     171                        else:
     172                                if equal_width_length != 0 and len( part ) > equal_width_length:
     173                                        equal_width_length = len( part )
     174
     175                                numbers_chars.append( part )
     176
     177                if equal_width_length > 0:
     178                        tmplist = list()
     179
     180                        for number_char in numbers_chars:
     181                                try:
     182                                        nnum = int( number_char )
     183                                        tmplist.append( '%0*d' % (equal_width_length, nnum) )
     184                                except ValueError:
     185                                        tmplist.append( number_char )
     186                       
     187                        numbers_chars = tmplist
     188
     189                return numbers_chars
     190
     191        def combine( self, pre, post):
     192                '''
     193                This method is used to combine a possibility of a combination
     194                '''
     195                if pre == '':
     196                        return post
     197                else:
     198                        return '%s %s' % (pre, post)
     199
     200        def combinations( self, listin, prefix=''):
     201                '''
     202                This method creates from the given ranges all possible combinations
     203                '''
     204                outlist = list()
     205
     206                if len( listin ) > 1:
     207                        for item in listin[0]:
     208                                outlist += self.combinations( listin[1:], self.combine( prefix, str( item ) ) )
     209                else:
     210                        for item in listin[0]:
     211                                outlist.append( tuple( self.combine( prefix, str( item ) ).split( ' ') ) )
     212
     213                return outlist
     214
     215        def args_parser(self, args):
     216                '''
     217                This method checks all given extra arguments for the given ranges between the
     218                [ and ]
     219                '''
     220                findregex = re.compile( r'\[([0-9a-z\-,]+)\]', re.VERBOSE )
     221                nodenames = list()
     222
     223                for arg in args:
     224                        found = findregex.findall( arg )
     225                        ranges = list()
     226
     227                        if found:
     228                                pattern = findregex.sub( '%s', arg )
     229
     230                                for part in found:
     231                                        ranges.append( self.return_range( part ) )
     232
     233                                combs = self.combinations( ranges )
     234
     235                                for comb in combs:
     236                                        # Here the %s in the pattern are
     237                                        # replaced by the correct value
     238                                        nodenames.append( pattern % comb )
     239                        else:
     240                                nodenames.append( arg )
     241
     242                return nodenames
     243
     244        def check_values(self, values, args):
     245                '''
     246                Here we override the default method in OptionParser to
     247                enable our extra parsing on the given Arguments
     248                '''
     249                return values, self.args_parser( args )
     250
     251#### End Useful Class #####
     252
     253def sanitize_jobs( jobs ):
     254
     255    ljobs = list()
     256
     257    for job in jobs:
     258        ljobs.extend( re.findall( r'[0-9]+\/([0-9]+)\.*.', job ) )
     259
     260    return list( set( ljobs ) )
     261
     262def parse_nodename( nodename ):
     263    global NODE_EXPR
     264
     265    parts = re.search( r'%s' % NODE_EXPR, nodename, re.VERBOSE )
     266
     267    try:
     268        racknr = parts.group( 'racknr' )
     269    except Exception:
     270                racknr = 0
     271
     272    try:
     273        nodenr = parts.group( 'nodenr' )
     274    except Exception:
     275        nodenr = 0
     276
     277    return int( racknr ), int( nodenr )
     278
     279def get_nodes( racknode=False, hosts=None ):
     280    global LENGTH_NODE
     281    global LENGTH_STATE
     282    global OPT_SERVERNAME
     283
     284    nodes_dict = dict()
     285
     286    try:
     287        if not OPT_SERVERNAME:
     288            p = PBSQuery()
     289        else:
     290            p = PBSQuery( OPT_SERVERNAME )
     291    except PBSError, reason:
     292        print 'Error: %s' % reason
     293        sys.exit( -1 )
     294
     295    p.new_data_structure()
     296
     297    attr = [ 'state', 'jobs', 'properties' ]
     298
     299    try:
     300        nodes = p.getnodes( attr )
     301    except PBSError, reason:
     302        print 'Error: %s' % reason
     303        sys.exit( -1 )
     304
     305    number_of_racks = 0
     306    nodes_per_rack = 0
     307    hosts_list = list()
     308   
     309    for node, attr in nodes.items():
     310        if node in EXCLUDE_NODES:
     311            continue
     312
     313        if hosts and node not in hosts:
     314            continue
     315
     316        if pbs.ND_down in attr.state:
     317            state = pbs.ND_down
     318        else:
     319            state = attr.state[ 0 ]
     320
     321        state_char = PBS_STATES[ state ]
     322
     323        if attr.is_free() and attr.has_job():
     324            state = pbs.ND_busy
     325            state_char = PBS_STATES[ pbs_ND_single ]
     326
     327        if not nodes_dict.has_key( node ):
     328            nodes_dict[ node ] = dict()
     329
     330        # Setting the longest lenght
     331        if len( node ) > LENGTH_NODE:
     332            LENGTH_NODE = len( node )
     333
     334        if len( state ) > LENGTH_STATE:
     335            LENGTH_STATE = len( state )
     336
     337        if racknode:
     338            racknr, nodenr = parse_nodename( node )
     339
     340            if racknr > number_of_racks:
     341                number_of_racks = racknr
     342
     343            if nodenr > nodes_per_rack:
     344                nodes_per_rack = nodenr
     345           
     346            if not nodes_dict.has_key( racknr ):
     347                nodes_dict[ racknr ] = dict()
     348
     349            if not nodes_dict[ racknr ].has_key( nodenr ):
     350                nodes_dict[ racknr ][ nodenr ] = dict()
     351
     352            nodes_dict[ racknr ][ nodenr ][ 'state_char' ] = state_char
     353            nodes_dict[ racknr ][ nodenr ][ 'state' ] = state
     354       
     355            if attr.has_key( 'jobs' ):
     356                nodes_dict[ racknr ][ nodenr ][ 'jobs' ] = sanitize_jobs( attr.jobs )
     357            else:
     358                nodes_dict[ racknr ][ nodenr ][ 'jobs' ] = []
     359        else:
     360            hosts_list.append( node )
     361            nodes_dict[ node ][ 'state_char' ] = state_char
     362            nodes_dict[ node ][ 'state' ] = state
     363       
     364            if attr.has_key( 'jobs' ):
     365                nodes_dict[ node ][ 'jobs' ] = sanitize_jobs( attr.jobs )
     366            else:
     367                nodes_dict[ node ][ 'jobs' ] = []
     368
     369    if not racknode:
     370        return nodes_dict, hosts_list
     371
     372    return nodes_dict, number_of_racks, nodes_per_rack
     373
     374def _generate_index( str ):
     375    index = []
     376
     377    def _append( fragment, alist=index ):
     378        if fragment.isdigit():
     379            fragment = int( fragment )
     380        alist.append( fragment )
     381
     382    prev_isdigit = str[0].isdigit()
     383    current_fragment = ''
     384
     385    for char in str:
     386        curr_isdigit = char.isdigit()
     387
     388        if curr_isdigit == prev_isdigit:
     389            current_fragment += char
     390        else:
     391            _append( current_fragment )
     392            current_fragment = char
     393            prev_isdigit = curr_isdigit
     394
     395    _append( current_fragment )
     396
     397    return tuple( index )
     398
     399def real_sort( inlist ):
     400    indices = map(_generate_index, inlist )
     401    decorated = zip( indices, inlist )
     402    decorated.sort()
     403
     404    return [ item for index, item in decorated ]
     405
     406def print_table():
     407    global START_RACK
     408    global OPT_SKIP_EMPTY_RACKS
     409
     410    nodes, racknr, nodenr = get_nodes( True )
     411
     412    ## Code herebelow has been taken from the new_rack_pbsmon.py
     413    save_column = None
     414   
     415    print   
     416    print '  ',
     417    for rack in xrange( START_RACK, racknr + 1 ):
     418       
     419        if not ( rack % 10 ):
     420            char = '%d' % ( rack / 10 )
     421            save_column = char
     422        else:
     423            char = ' '
     424
     425        if OPT_SKIP_EMPTY_RACKS:
     426            if nodes.has_key( rack ):
     427                if save_column:
     428                    char = save_column
     429                    save_column = None
     430                print char,
     431        else:
     432            print char,
     433    print   
     434
     435    print '  ',
     436    for rack in xrange( START_RACK, racknr + 1 ):
     437       
     438        char = rack % 10
     439        if OPT_SKIP_EMPTY_RACKS:
     440            if nodes.has_key( rack ):
     441                print char,
     442        else:
     443            print char,
     444    print
     445
     446    for node in xrange( 1, nodenr + 1 ):
     447        print '%2d' % node,
     448
     449        for rack in xrange( START_RACK, racknr + 1 ):
     450            if OPT_SKIP_EMPTY_RACKS:
     451                if not nodes.has_key( rack ):
     452                    continue
     453            try:
     454                print nodes[ rack ][ node ][ 'state_char' ],
     455            except KeyError:
     456                print ' ',
     457        print
     458    print
     459
     460def print_table_summary():
     461    global PBS_STATES
     462    global OPT_SERVERNAME
     463
     464    try:
     465        if not OPT_SERVERNAME:
     466            p = PBSQuery()
     467        else:
     468            p = PBSQuery( OPT_SERVERNAME )
     469    except PBSError, reason:
     470        print 'error: %s' % reason
     471        sys.exit(-1)
     472
     473    # get the state of the nodes
     474    attr = [ 'state', 'jobs', 'properties' ]
     475    try:
     476        nodes = p.getnodes(attr)
     477    except PBSError, reason:
     478        print 'error: %s' % reason
     479        sys.exit(-1)
     480
     481    node_dict = {}
     482
     483    count_states = {}
     484    for key in PBS_STATES.keys():
     485        count_states[key] = 0
     486
     487    for nodename, node in nodes.items():
     488
     489        # Skip login nodes in status display
     490        #
     491        if not nodename.find('login'):
     492            continue
     493
     494        state = node['state'][ 0 ]
     495
     496        state_char = PBS_STATES[state]
     497        count_states[state] += 1
     498        count_states[pbs_ND_total] += 1
     499
     500        if node.is_free():                          # can happen for single CPU jobs
     501            if node.has_job():
     502#               print 'TD: %s' % nodename, node
     503                state_char = PBS_STATES[pbs_ND_single]
     504                count_states[pbs.ND_free] -=  1
     505                count_states[pbs_ND_single] += 1
     506            else:
     507                if  'infiniband' in node['properties']:
     508                    count_states[pbs_ND_free_parallel] +=  1
     509                elif  'ifiniband' in node['properties']:
     510                    count_states[pbs_ND_free_serial] +=  1
     511                #else:
     512                #   count_states[pbs_ND_free_serial] +=  1
     513               
     514#       print 'TD: %s %s' % (nodename, state_char)
     515        dummy = nodename.split('-')
     516        if len( dummy ) > 1:
     517            node_dict[dummy[1]] = state_char
     518        else:
     519            node_dict[dummy[0]] = state_char
     520
     521    legend = PBS_STATES.keys()
     522    legend.sort()
     523
     524    n = 0
     525    for state in legend:
     526        print '  %s  %-13s : %-5d' % (PBS_STATES[state], state, count_states[state]),
     527
     528        n = n + 1
     529        if not (n & 1):
     530            print
     531
     532def print_extended( hosts=None ):
     533    global LENGTH_NODE
     534    global LENGTH_STATE
     535    global EXTENDED_PATTERNS
     536   
     537    nodes, ihosts = get_nodes( hosts=hosts )
     538    row_header = EXTENDED_PATTERNS[ 'header' ] % ( ( LENGTH_NODE + 2 ), 'Node', ( LENGTH_STATE + 2 ), 'State', 'Jobs' )
     539    LENGTH_ROW = len( row_header )
     540
     541    rows_str = list()
     542    ihosts = real_sort( ihosts )
     543
     544    for node in ihosts:
     545        attr = nodes[ node ]
     546        row_str = EXTENDED_PATTERNS[ 'row' ] % ( ( LENGTH_NODE + 2 ), node, ( LENGTH_STATE + 2 ), attr[ 'state' ], ','.join( attr[ 'jobs' ] ) )
     547
     548        if len( row_str ) > LENGTH_ROW:
     549            LENGTH_ROW = len( row_str )
     550
     551        rows_str.append( row_str )
     552
     553    print
     554    print row_header
     555    print EXTENDED_PATTERNS[ 'line' ] % ( EXTENDED_PATTERNS[ 'line_char' ] * LENGTH_ROW )
     556    print '\n'.join( rows_str )
     557    print
    359558
    360559if __name__ == '__main__':
    361         PROGNAME = os.path.basename(sys.argv[0])
    362         getopts()
    363 
    364         if OPT_NODESTATUS:
    365                 pbsmon(OPT_SERVERNAME)
    366 
    367         if OPT_SUMMARY:
    368                 print 'Summary:'
    369                 pbsmon_summary(OPT_SERVERNAME)
    370 
    371         sys.exit(0)
    372 
    373 # EOB
    374 
     560   
     561    parser = AdvancedParser(usage=__doc__)
     562
     563    parser.add_option( "-t", "--table", dest="table", action="store_true", help="Show an table" )
     564    parser.add_option( "-l", "--list", dest="extended", action="store_true", help="Show node rows with state and jobinfo" )
     565    parser.add_option( "-s", "--summary", dest="summary", action="store_true", help="Display a short summary" )
     566    parser.add_option( "-w", "--wide", dest="wide", action="store_true", help="Wide display for node status ( only when -t is used )" )
     567    parser.add_option( "-S", "--servername", dest="servername", help="Change the default servername" )
     568
     569    parser.set_defaults( table=PRINT_TABLE )
     570    parser.set_defaults( summary=False )
     571    parser.set_defaults( extended=PRINT_EXTENDED )
     572    parser.set_defaults( servername=None )
     573
     574    ( options, args ) = parser.parse_args()
     575
     576    if options.servername:
     577        OPT_SERVERNAME = options.servername
     578
     579    if options.wide:
     580        OPT_SKIP_EMPTY_RACKS = False
     581
     582    if args:
     583        options.extended = True
     584
     585    if options.extended and PRINT_TABLE:
     586        options.table = False
     587
     588    if options.table and PRINT_EXTENDED:
     589        options.extended = False
     590
     591    if options.extended:
     592        print_extended( args )
     593    elif options.table:
     594        print_table()
     595    else:
     596        print 'Something is wrong, bye!'
     597        sys.exit( -1 )
     598
     599    if options.summary:
     600        print_table_summary()
Note: See TracChangeset for help on using the changeset viewer.