pbs_mom_dynamic_resource.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. from tests.functional import *
  37. class TestMomDynRes(TestFunctional):
  38. filenames = []
  39. def create_mom_resources(self, resc_name, resc_type, resc_flag,
  40. script_body):
  41. """
  42. helper function for creating mom_resource.
  43. """
  44. fp_list = []
  45. resc_name_mom = ",".join(resc_name)
  46. resc_name_svr = resc_name_mom
  47. resc_name_mom = '"' + resc_name_mom + '"'
  48. self.scheduler.set_sched_config({'mom_resources': resc_name_mom},
  49. validate=True)
  50. self.scheduler.add_resource(resc_name_svr)
  51. ln = len(resc_name)
  52. for i in range(ln):
  53. attr = {"type": resc_type[i], "flag": resc_flag[i]}
  54. self.server.manager(MGR_CMD_CREATE, RSC, attr,
  55. id=resc_name[i], expect=True)
  56. fp = self.du.create_temp_file(prefix="mom_resc", suffix=".scr",
  57. body=script_body[i])
  58. self.du.chmod(path=fp, mode=0755)
  59. mom_config_str = "!" + fp
  60. self.mom.add_config({resc_name[i]: mom_config_str})
  61. fp_list.append(fp)
  62. self.filenames.append(fp)
  63. return fp_list
  64. def test_res_string_incorrect_value(self):
  65. """
  66. Test for host level string resource
  67. with string mom dynamic value
  68. """
  69. resc_name = ["foo"]
  70. resc_type = ["string"]
  71. resc_flag = ["h"]
  72. script_body = ["/bin/echo pqr"]
  73. self.create_mom_resources(resc_name, resc_type, resc_flag, script_body)
  74. # Submit a job that requests different mom dynamic resource
  75. # not return from script
  76. attr = {"Resource_List." + resc_name[0]: 'abc'}
  77. j = Job(TEST_USER, attrs=attr)
  78. jid = self.server.submit(j)
  79. # The job shouldn't run
  80. c = "Can Never Run: Insufficient amount of resource: foo (abc != pqr)"
  81. self.server.expect(JOB, {'job_state': 'Q', 'comment': c},
  82. id=jid, attrop=PTL_AND)
  83. def test_res_string_array_value(self):
  84. """
  85. Test for host level string_array resource
  86. with string mom dynamic value
  87. """
  88. resc_name = ["foo"]
  89. resc_type = ["string_array"]
  90. resc_flag = ["h"]
  91. script_body = ["/bin/echo red,green,blue"]
  92. self.create_mom_resources(resc_name, resc_type, resc_flag, script_body)
  93. # Submit a job that requests mom dynamic resource
  94. attr = {"Resource_List." + resc_name[0]: 'red'}
  95. j = Job(TEST_USER, attrs=attr)
  96. jid = self.server.submit(j)
  97. # The job should run
  98. self.server.expect(JOB, {'job_state': 'R'}, id=jid)
  99. # Submit a job that requests different mom dynamic resource
  100. # not return from script
  101. attr = {"Resource_List." + resc_name[0]: 'white'}
  102. j = Job(TEST_USER, attrs=attr)
  103. jid = self.server.submit(j)
  104. # The job shouldn't run
  105. c = "Can Never Run: Insufficient amount of resource:"
  106. c += " foo (white != red,green,blue)"
  107. self.server.expect(JOB, {'job_state': 'Q', 'comment': c},
  108. id=jid, attrop=PTL_AND)
  109. def test_res_string_perticular_value(self):
  110. """
  111. Test for host level string resource
  112. with mom dynamic value “This is a test”
  113. """
  114. resc_name = ["foo"]
  115. resc_type = ["string"]
  116. resc_flag = ["h"]
  117. script_body = ["/bin/echo This is a test"]
  118. self.create_mom_resources(resc_name, resc_type, resc_flag, script_body)
  119. # Submit a job that requests different mom dynamic resource
  120. attr = {"Resource_List." + resc_name[0]: 'red'}
  121. j = Job(TEST_USER, attrs=attr)
  122. jid = self.server.submit(j)
  123. # The job shouldn't run
  124. c = "Can Never Run: Insufficient amount of resource:"
  125. c += " foo (red != This is a test)"
  126. self.server.expect(JOB, {'job_state': 'Q', 'comment': c},
  127. id=jid, attrop=PTL_AND)
  128. # Submit a job that requests mom dynamic resource
  129. attr = {"Resource_List." + resc_name[0]: '"This is a test"'}
  130. j = Job(TEST_USER, attrs=attr)
  131. jid = self.server.submit(j)
  132. # The job should run
  133. self.server.expect(JOB, {'job_state': 'R'}, id=jid)
  134. def test_res_string_correct_value(self):
  135. """
  136. Test for host level string resource
  137. with string mom dynamic value
  138. """
  139. resc_name = ["foo"]
  140. resc_type = ["string"]
  141. resc_flag = ["h"]
  142. script_body = ["/bin/echo abc"]
  143. self.create_mom_resources(resc_name, resc_type, resc_flag, script_body)
  144. # Submit a job that requests mom dynamic resource
  145. attr = {"Resource_List." + resc_name[0]: 'abc'}
  146. j = Job(TEST_USER, attrs=attr)
  147. jid = self.server.submit(j)
  148. # The job should run
  149. self.server.expect(JOB, {'job_state': 'R'}, id=jid)
  150. def test_res_float_value(self):
  151. """
  152. host level consumable float resource with mom dynamic value float
  153. """
  154. resc_name = ["foo"]
  155. resc_type = ["float"]
  156. resc_flag = ["nh"]
  157. script_body = ["/bin/echo 3"]
  158. self.create_mom_resources(resc_name, resc_type, resc_flag, script_body)
  159. # Submit a job that requests more value for the mom resource
  160. # than available
  161. attr = {"Resource_List." + resc_name[0]: 4}
  162. j = Job(TEST_USER, attrs=attr)
  163. jid = self.server.submit(j)
  164. # The job shouldn't run
  165. c = "Can Never Run:"
  166. c += " Insufficient amount of resource: foo (R: 4 A: 3 T: 3)"
  167. self.server.expect(JOB, {'job_state': 'Q', 'comment': c},
  168. id=jid, attrop=PTL_AND)
  169. # Submit a job that requests less value for the mom resource
  170. # than available
  171. attr = {"Resource_List." + resc_name[0]: 2}
  172. j = Job(TEST_USER, attrs=attr)
  173. jid = self.server.submit(j)
  174. # The job should run
  175. self.server.expect(JOB, {'job_state': 'R',
  176. 'Resource_List.'+resc_name[0]: '2'},
  177. id=jid, attrop=PTL_AND)
  178. def test_multiple_res_valid_value(self):
  179. """
  180. multiple host level resource long,float with all correct values.
  181. Submit different jobs with different resource types
  182. """
  183. resc_name = ["foo", "foo1"]
  184. resc_type = ["float", "long"]
  185. script_body = ["/bin/echo 3", "/bin/echo 4"]
  186. resc_flag = ["nh", "nh"]
  187. self.create_mom_resources(resc_name, resc_type,
  188. resc_flag, script_body)
  189. # Submit a job that requests mom dynamic resource
  190. attr = {"Resource_List." + resc_name[0]: 2,
  191. "Resource_List." + resc_name[1]: 3}
  192. j = Job(TEST_USER, attrs=attr)
  193. jid = self.server.submit(j)
  194. # The job should run
  195. self.server.expect(JOB, {'job_state': 'R'}, id=jid)
  196. # Submit a job that requests more value
  197. # than available for both mom resources.
  198. attr = {"Resource_List." + resc_name[0]: 4,
  199. "Resource_List." + resc_name[1]: 4}
  200. j = Job(TEST_USER, attrs=attr)
  201. jid = self.server.submit(j)
  202. # The job shouldn't run
  203. c = "Can Never Run:"
  204. c += " Insufficient amount of resource: foo (R: 4 A: 3 T: 3)"
  205. self.server.expect(JOB, {'job_state': 'Q', 'comment': c},
  206. id=jid, attrop=PTL_AND)
  207. def test_multiple_res_invalid_value(self):
  208. """
  209. multiple host level resource with one or more incorrect values.
  210. Submit different jobs with different resource types
  211. """
  212. resc_name = ["foo", "foo1"]
  213. resc_type = ["float", "size"]
  214. script_body = ["/bin/echo 3", "/bin/echo -2"]
  215. resc_flag = ["nh", "nh"]
  216. self.create_mom_resources(resc_name, resc_type,
  217. resc_flag, script_body)
  218. # Submit a job that requests mom dynamic resource
  219. attr = {"Resource_List." + resc_name[0]: 2,
  220. "Resource_List." + resc_name[1]: 1}
  221. j = Job(TEST_USER, attrs=attr)
  222. jid = self.server.submit(j)
  223. # The job shouldn't run
  224. c = "Can Never Run:"
  225. c += " Insufficient amount of resource: foo1 (R: 1kb A: 0kb T: 0kb)"
  226. self.server.expect(JOB, {'job_state': 'Q', 'comment': c},
  227. id=jid, attrop=PTL_AND)
  228. def test_delete_res(self):
  229. """
  230. delete a resource while jobs are running/queued.
  231. """
  232. message = "Resource busy on job"
  233. resc_name = ["foo"]
  234. resc_type = ["string"]
  235. resc_flag = ["h"]
  236. script_body = ["/bin/echo abc"]
  237. self.create_mom_resources(resc_name, resc_type, resc_flag, script_body)
  238. # Submit a job that requests mom dynamic resource
  239. attr = {"Resource_List." + resc_name[0]: 'abc'}
  240. j = Job(TEST_USER, attrs=attr)
  241. jid = self.server.submit(j)
  242. # The job should run
  243. self.server.expect(JOB, {'job_state': 'R'}, id=jid)
  244. # Check for the expected error message throwing by PBS
  245. try:
  246. self.server.manager(MGR_CMD_DELETE, RSC, id='foo')
  247. except PbsManagerError as e:
  248. self.assertTrue(message in e.msg[0])
  249. def test_alter_res_value(self):
  250. """
  251. Verify that altered mom dynamic resource value will take affect
  252. only when a job is rerun
  253. """
  254. resc_name = ["foo"]
  255. resc_type = ["float"]
  256. resc_flag = ["nh"]
  257. script_body = ["/bin/echo 3"]
  258. filename = self.create_mom_resources(resc_name, resc_type,
  259. resc_flag, script_body)
  260. # Submit a job that requests mom dynamic resource
  261. attr = {"Resource_List." + resc_name[0]: '2'}
  262. j = Job(TEST_USER, attrs=attr)
  263. jid = self.server.submit(j)
  264. # The job should run
  265. self.server.expect(JOB, {'job_state': 'R'}, id=jid)
  266. with open(filename[0], "wb") as fd:
  267. fd.truncate()
  268. fd.write("echo 1")
  269. self.server.rerunjob(jobid=jid)
  270. # The job shouldn't run
  271. c = "Can Never Run:"
  272. c += " Insufficient amount of resource: foo (R: 2 A: 1 T: 1)"
  273. self.server.expect(JOB, {'job_state': 'Q', 'comment': c},
  274. id=jid, attrop=PTL_AND)
  275. def tearDown(self):
  276. #removing all files creating in test
  277. for i in self.filenames:
  278. if os.path.isfile(i):
  279. os.remove(i)