pbs_crayutils.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. # coding: utf-8
  2. # Copyright (C) 1994-2018 Altair Engineering, Inc.
  3. # For more information, contact Altair at www.altair.com.
  4. #
  5. # This file is part of the PBS Professional ("PBS Pro") software.
  6. #
  7. # Open Source License Information:
  8. #
  9. # PBS Pro is free software. You can redistribute it and/or modify it under the
  10. # terms of the GNU Affero General Public License as published by the Free
  11. # Software Foundation, either version 3 of the License, or (at your option) any
  12. # later version.
  13. #
  14. # PBS Pro is distributed in the hope that it will be useful, but WITHOUT ANY
  15. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. # FOR A PARTICULAR PURPOSE.
  17. # See the GNU Affero General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU Affero General Public License
  20. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. #
  22. # Commercial License Information:
  23. #
  24. # For a copy of the commercial license terms and conditions,
  25. # go to: (http://www.pbspro.com/UserArea/agreement.html)
  26. # or contact the Altair Legal Department.
  27. #
  28. # Altair’s dual-license business model allows companies, individuals, and
  29. # organizations to create proprietary derivative works of PBS Pro and
  30. # distribute them - whether embedded or bundled with other software -
  31. # under a commercial license agreement.
  32. #
  33. # Use of Altair’s trademarks, including but not limited to "PBS™",
  34. # "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
  35. # trademark licensing policies.
  36. import socket
  37. import os
  38. from ptl.utils.pbs_dshutils import DshUtils
  39. from ptl.lib.pbs_ifl_mock import *
  40. class CrayUtils(object):
  41. """
  42. Cray specific utility class
  43. """
  44. node_status = []
  45. node_summary = {}
  46. cmd_output = []
  47. du = None
  48. def __init__(self):
  49. self.du = DshUtils()
  50. (self.node_status, self.node_summary) = self.parse_apstat_rn()
  51. def call_apstat(self, options):
  52. """
  53. Build the apstat command and run it. Return the output of the command.
  54. :param options: options to pass to apstat command
  55. :type options: str
  56. :returns: the command output
  57. """
  58. hostname = socket.gethostname()
  59. platform = self.du.get_platform(hostname)
  60. apstat_env = os.environ
  61. apstat_cmd = "apstat"
  62. if 'cray' not in platform:
  63. return None
  64. if 'craysim' in platform:
  65. lib_path = '$LD_LIBRARY_PATH:/opt/alps/tester/usr/lib/'
  66. apstat_env['LD_LIBRARY_PATH'] = lib_path
  67. apstat_env['ALPS_CONFIG_FILE'] = '/opt/alps/tester/alps.conf'
  68. apstat_env['apsched_sharedDir'] = '/opt/alps/tester/'
  69. apstat_cmd = "/opt/alps/tester/usr/bin/apstat -d ."
  70. cmd_run = self.du.run_cmd(hostname, [apstat_cmd, options],
  71. as_script=True, wait_on_script=True,
  72. env=apstat_env)
  73. return cmd_run
  74. def parse_apstat_rn(self):
  75. """
  76. Parse the apstat command output for node status and summary
  77. :type options: str
  78. :returns: tuple of (node status, node summary)
  79. """
  80. status = []
  81. summary = {}
  82. count = 0
  83. options = '-rn'
  84. cmd_run = self.call_apstat(options)
  85. if cmd_run is None:
  86. return (status, summary)
  87. cmd_result = cmd_run['out']
  88. keys = cmd_result[0].split()
  89. # Add a key 'Mode' because 'State' is composed of two list items, e.g:
  90. # State = 'UP B', where Mode = 'B'
  91. k2 = ['Mode']
  92. keys = keys[0:3] + k2 + keys[3:]
  93. cmd_iter = iter(cmd_result)
  94. for line in cmd_iter:
  95. if count == 0:
  96. count = 1
  97. continue
  98. if "Compute node summary" in line:
  99. summary_line = next(cmd_iter)
  100. summary_keys = summary_line.split()
  101. summary_data = next(cmd_iter).split()
  102. sum_index = 0
  103. for a in summary_keys:
  104. summary[a] = summary_data[sum_index]
  105. sum_index += 1
  106. break
  107. obj = {}
  108. line = line.split()
  109. for i, value in enumerate(line):
  110. obj[keys[i]] = value
  111. if keys[i] == 'State':
  112. obj[keys[i]] = value + " " + line[i + 1]
  113. # If there is no Apids in the apstat then use 'None' as the value
  114. if "Apids" in obj:
  115. pass
  116. else:
  117. obj["Apids"] = None
  118. status.append(obj)
  119. return (status, summary)
  120. def count_node_summ(self, cnsumm='up'):
  121. """
  122. Return the value of any one of the following parameters as shown in
  123. the 'Compute Node Summary' section of 'apstat -rn' output:
  124. arch, config, up, resv, use, avail, down
  125. :param cnsumm: parameter which is being queried, defaults to 'up'
  126. :type cnsumm: str
  127. :returns: value of parameter being queried
  128. """
  129. return int(self.node_summary[cnsumm])
  130. def count_node_state(self, state='UP B'):
  131. """
  132. Return how many nodes have a certain 'State' value.
  133. :param state: parameter which is being queried, defaults to 'UP B'
  134. :type state: str
  135. :returns: count of how many nodes have the state
  136. """
  137. count = 0
  138. status = self.node_status
  139. for stat in status:
  140. if stat['State'] == state:
  141. count += 1
  142. return count
  143. def get_numthreads(self, nid):
  144. """
  145. Returns the number of hyperthread for the given node
  146. """
  147. options = '-N %d -n -f "nid,c/cu"' % int(nid)
  148. cmd_run = self.call_apstat(options)
  149. if cmd_run is None:
  150. return None
  151. cmd_result = cmd_run['out']
  152. cmd_iter = iter(cmd_result)
  153. numthreads = 0
  154. for line in cmd_iter:
  155. if "Compute node summary" in line:
  156. break
  157. elif "NID" in line:
  158. continue
  159. else:
  160. key = line.split()
  161. numthreads = int(key[1])
  162. return numthreads
  163. def num_compute_vnodes(self, server):
  164. """
  165. Count the Cray compute nodes and return the value.
  166. """
  167. vnl = server.filter(MGR_OBJ_NODE,
  168. {'resources_available.vntype': 'cray_compute'})
  169. return len(vnl["resources_available.vntype=cray_compute"])