qianmo_job

self mode

  1. // ==UserScript==
  2. // @name qianmo_job
  3. // @version 0.0.3
  4. // @include http://newqianmo.baidu.com/404
  5. // @description self mode
  6. // @run-at document-start
  7. // @namespace https://greasyfork.org/users/164996
  8. // ==/UserScript==
  9. const head = `<meta charset="UTF-8" />
  10. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  11. <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  12. <title>job</title>
  13. <style>
  14. body {
  15. user-select: none;
  16. cursor: pointer;
  17. margin: 0;
  18. }
  19. #table {
  20. display: grid;
  21. grid-template-columns: repeat(9, auto);
  22. grid-column-gap: 1em;
  23. }
  24. #node {
  25. #width: fit-content;
  26. display: grid;
  27. grid-template-columns: repeat(6, auto);
  28. grid-column-gap: 1em;
  29. color: #9E9E9E;
  30. }
  31. div.running {
  32. color: #2196F3;
  33. }
  34. div.other {
  35. color: #9E9E9E;
  36. }
  37. div.cancelled {
  38. color: #FF5722;
  39. }
  40. div.failed {
  41. color: #E91E63;
  42. }
  43. div.completed {
  44. color: #673AB7;
  45. }
  46. div.pending {
  47. color: #FF9800;
  48. }
  49. div.preempted {
  50. color: #3f51b5;
  51. }
  52. #disconnect{
  53. display: none;
  54. color: #bbb;
  55. position: fixed;
  56. left: 50%;
  57. transform: translateX(-50%);
  58. }
  59. span.button{
  60. user-select:none;
  61. cursor:pointer;
  62. }
  63. div.section{
  64. grid-column: 1 / -1;
  65. }
  66. iframe{
  67. display: none;
  68. }
  69. </style>`
  70. const body = `<div id="app">
  71. <div id='disconnect'>disconnect</div>
  72. <div id="node"></div>
  73. <div id="table"></div>
  74. <iframe src="http://newqianmo.baidu.com/index.jsp#/console"></iframe>
  75. </div>`
  76. document.head.innerHTML = head
  77. document.body.innerHTML = body
  78. const timeout = 10000
  79. const app = document.querySelector('#app')
  80. const node = document.querySelector('#node')
  81. const table = document.querySelector('#table')
  82. const disconnect = document.querySelector('#disconnect')
  83. const copy = text => {
  84. const textArea = document.createElement('textarea')
  85. textArea.value = text
  86. document.body.appendChild(textArea)
  87. textArea.select()
  88. document.execCommand('copy')
  89. document.body.removeChild(textArea)
  90. }
  91. const parse = s => {
  92. const t = document.implementation.createHTMLDocument()
  93. t.body.innerHTML = s
  94. return t
  95. }
  96. const fetchWithTimeout = (url, options) => {
  97. return Promise.race([
  98. fetch(url, options),
  99. new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
  100. ])
  101. }
  102. const fetchList = async url => {
  103. let data = await fetchWithTimeout(url)
  104. data = await data.json()
  105. data = data.retData.rows
  106. return data
  107. }
  108. const fetchResource = async () => {
  109. const url =
  110. 'http://newqianmo.baidu.com/action/gpu/queryGpuResource?pageNum=1&pageSize=5&isPersonal=1'
  111. return await fetchList(url)
  112. }
  113. const fetchTask = async (type = '', size = 20) => {
  114. const url = `http://newqianmo.baidu.com/action/gpu/queryGpuJobListPerson?pageNum=1&pageSize=${size}&isProjectList=0&jobId=&jobName=&queueName=&status=`
  115. return await fetchList(url + type)
  116. }
  117. const main = async () => {
  118. let data
  119. try {
  120. data = (await Promise.all([
  121. fetchTask('RUNNING'),
  122. fetchTask('PENDING', 5),
  123. fetchTask('FAILED', 5),
  124. fetchTask('PREEMPTED', 5),
  125. fetchTask('CANCELLED', 5)
  126. //fetchTask('COMPLETED', 5),
  127. ]))
  128. .filter(i => i)
  129. .flat()
  130. } catch (err) {
  131. disconnect.style.display = 'block'
  132. return
  133. }
  134. disconnect.style.display = 'none'
  135. let type_pre = ''
  136. let b = data.reduce((a, c) => {
  137. let url = ''
  138. try {
  139. url = new URL(c.jobLogUrl)
  140. url.pathname = ''
  141. url.port = 8825
  142. } catch {}
  143. const link = `<a target="_blank" href="${url}">tb</a>
  144. <a target="_blank" href="${c.jobLogUrl}">job</a>
  145. <a target="_blank" href="${c.workspaceUrl}">workspace</a>`
  146. url = url.hostname
  147. const ssh_action = `ssh slurm@${url} -t 'cd job/tmp/job-${c.slurmId};bash'`
  148. const rsync_action = `rsync -av slurm@${url}:job/tmp/job-${c.slurmId}/cdsr/runs .`
  149. const action = `<span class=button data-copy="${ssh_action}">ssh</span>
  150. <span class=button data-copy="${rsync_action}">rsync</span>
  151. <span class=button data-copy="deljob -j${c.jobId}">deljob</span>`
  152. const list = [
  153. c.jobName,
  154. c.jobId,
  155. c.priority,
  156. c.queueName,
  157. c.ncpus,
  158. c.gpuRatio,
  159. c.elapsed,
  160. action,
  161. link
  162. ]
  163. const type = c.status.toLowerCase()
  164. if (type !== type_pre) {
  165. type_pre = type
  166. a += `<div class="section ${type}">${type}</div>`
  167. }
  168. const row = list.map(i => `<div class=${type}>` + i + '</div>').join('')
  169. return a + row
  170. }, '')
  171. // node
  172. data = await fetchResource()
  173. let d = data.reduce((a, c) => {
  174. const list = [
  175. c.queueName,
  176. c.gpuType + ' x ' + c.gpuPerNode,
  177. Number(c.quota) - Number(c.used)
  178. ]
  179. const row = list.map(i => `<div>` + i + '</div>').join('')
  180. return a + row
  181. }, '')
  182. requestAnimationFrame(() => {
  183. node.innerHTML = d
  184. table.innerHTML = b
  185. })
  186. }
  187. main()
  188. let timer = setInterval(main, timeout)
  189. let changeTimer
  190. document.addEventListener('click', e => {
  191. const type = e.target.textContent
  192. const target = e.target
  193. let text = ''
  194. if (['ssh', 'rsync', 'deljob'].includes(type)) {
  195. text = target.dataset.copy
  196. } else if (target.children.length === 0) {
  197. text = target.textContent.trim()
  198. }
  199. if (text.length === 0) return
  200. copy(text)
  201. })
  202. document.addEventListener('visibilitychange', () => {
  203. clearTimeout(changeTimer)
  204. if (document.hidden) {
  205. changeTimer = setTimeout(() => clearInterval(timer), timeout)
  206. } else {
  207. main()
  208. clearInterval(timer)
  209. timer = setInterval(main, timeout)
  210. }
  211. })
  212.  
  213. const frame = document.querySelector('iframe')
  214. setInterval(() => {
  215. frame.contentWindow.location.reload()
  216. }, 1000 * 3600)